From 75b955380abf0cf6f9174f753c3ae72dd6b0a820 Mon Sep 17 00:00:00 2001 From: Vladimir Burian Date: Mon, 14 Feb 2011 14:09:49 +0100 Subject: [PATCH 1/1] Local copy of Plasma MIPS project. See project homepage at . Actual trunk directory is copied. --- kernel/dll.h | 537 ++++ kernel/dlltest.c | 38 + kernel/ethernet.c | 428 +++ kernel/filesys.c | 767 +++++ kernel/flash.c | 52 + kernel/http.c | 230 ++ kernel/libc.c | 658 ++++ kernel/makefile | 192 ++ kernel/math.c | 692 +++++ kernel/netutil.c | 1159 ++++++++ kernel/os_stubs.c | 71 + kernel/rtos.c | 1508 ++++++++++ kernel/rtos.h | 377 +++ kernel/rtos_test.c | 522 ++++ kernel/tcpip.c | 1737 +++++++++++ kernel/tcpip.h | 131 + kernel/uart.c | 549 ++++ tools/bintohex.c | 64 + tools/boot.asm | 239 ++ tools/bootldr.c | 265 ++ tools/convert.c | 258 ++ tools/count.c | 142 + tools/cpu.gif | Bin 0 -> 10775 bytes tools/ddr_init.c | 88 + tools/etermip.c | 448 +++ tools/makefile | 284 ++ tools/mlite.c | 999 +++++++ tools/no_os.c | 54 + tools/opcodes.asm | 1108 +++++++ tools/output.txt | 43 + tools/pi.c | 35 + tools/plasma.h | 52 + tools/ram_image.c | 133 + tools/test.c | 237 ++ tools/tracehex.c | 177 ++ vhdl/alu.vhd | 61 + vhdl/build_dir/ISE_scripts/.svn/all-wcprops | 23 + vhdl/build_dir/ISE_scripts/.svn/entries | 130 + .../.svn/text-base/loadprom.cmds.svn-base | 6 + .../.svn/text-base/main.scrs.svn-base | 7 + .../.svn/text-base/makeprom.cmds.svn-base | 8 + vhdl/build_dir/ISE_scripts/loadprom.cmds | 6 + vhdl/build_dir/ISE_scripts/main.scrs | 7 + vhdl/build_dir/ISE_scripts/makeprom.cmds | 8 + vhdl/build_dir/Makefile | 144 + vhdl/bus_mux.vhd | 136 + vhdl/cache.vhd | 177 ++ vhdl/code.txt | 658 ++++ vhdl/control.vhd | 482 +++ vhdl/ddr_ctrl.vhd | 354 +++ vhdl/eth_dma.vhd | 183 ++ vhdl/makefile | 119 + vhdl/mem_ctrl.vhd | 196 ++ vhdl/mlite_cpu.vhd | 342 +++ vhdl/mlite_pack.vhd | 563 ++++ vhdl/mult.vhd | 207 ++ vhdl/pc_next.vhd | 71 + vhdl/pipeline.vhd | 139 + vhdl/plasma.vhd | 320 ++ vhdl/plasma_3e.vhd | 289 ++ vhdl/plasma_S3E.npl | 38 + vhdl/plasma_if.ucf | 111 + vhdl/plasma_if.vhd | 152 + vhdl/ram.vhd | 176 ++ vhdl/ram_xilinx.vhd | 2641 +++++++++++++++++ vhdl/reg_bank.vhd | 375 +++ vhdl/shifter.vhd | 65 + vhdl/simili.cmd | 8 + vhdl/spartan3e.ucf | 279 ++ vhdl/tbench.vhd | 119 + vhdl/uart.vhd | 181 ++ 71 files changed, 23055 insertions(+) create mode 100644 kernel/dll.h create mode 100644 kernel/dlltest.c create mode 100644 kernel/ethernet.c create mode 100644 kernel/filesys.c create mode 100644 kernel/flash.c create mode 100644 kernel/http.c create mode 100644 kernel/libc.c create mode 100644 kernel/makefile create mode 100644 kernel/math.c create mode 100644 kernel/netutil.c create mode 100644 kernel/os_stubs.c create mode 100644 kernel/rtos.c create mode 100644 kernel/rtos.h create mode 100644 kernel/rtos_test.c create mode 100644 kernel/tcpip.c create mode 100644 kernel/tcpip.h create mode 100644 kernel/uart.c create mode 100644 tools/bintohex.c create mode 100644 tools/boot.asm create mode 100644 tools/bootldr.c create mode 100644 tools/convert.c create mode 100644 tools/count.c create mode 100644 tools/cpu.gif create mode 100644 tools/ddr_init.c create mode 100644 tools/etermip.c create mode 100644 tools/makefile create mode 100644 tools/mlite.c create mode 100644 tools/no_os.c create mode 100644 tools/opcodes.asm create mode 100644 tools/output.txt create mode 100644 tools/pi.c create mode 100644 tools/plasma.h create mode 100644 tools/ram_image.c create mode 100644 tools/test.c create mode 100644 tools/tracehex.c create mode 100644 vhdl/alu.vhd create mode 100644 vhdl/build_dir/ISE_scripts/.svn/all-wcprops create mode 100644 vhdl/build_dir/ISE_scripts/.svn/entries create mode 100644 vhdl/build_dir/ISE_scripts/.svn/text-base/loadprom.cmds.svn-base create mode 100644 vhdl/build_dir/ISE_scripts/.svn/text-base/main.scrs.svn-base create mode 100644 vhdl/build_dir/ISE_scripts/.svn/text-base/makeprom.cmds.svn-base create mode 100644 vhdl/build_dir/ISE_scripts/loadprom.cmds create mode 100644 vhdl/build_dir/ISE_scripts/main.scrs create mode 100644 vhdl/build_dir/ISE_scripts/makeprom.cmds create mode 100644 vhdl/build_dir/Makefile create mode 100644 vhdl/bus_mux.vhd create mode 100644 vhdl/cache.vhd create mode 100644 vhdl/code.txt create mode 100644 vhdl/control.vhd create mode 100644 vhdl/ddr_ctrl.vhd create mode 100644 vhdl/eth_dma.vhd create mode 100644 vhdl/makefile create mode 100644 vhdl/mem_ctrl.vhd create mode 100644 vhdl/mlite_cpu.vhd create mode 100644 vhdl/mlite_pack.vhd create mode 100644 vhdl/mult.vhd create mode 100644 vhdl/pc_next.vhd create mode 100644 vhdl/pipeline.vhd create mode 100644 vhdl/plasma.vhd create mode 100644 vhdl/plasma_3e.vhd create mode 100644 vhdl/plasma_S3E.npl create mode 100644 vhdl/plasma_if.ucf create mode 100644 vhdl/plasma_if.vhd create mode 100644 vhdl/ram.vhd create mode 100644 vhdl/ram_xilinx.vhd create mode 100644 vhdl/reg_bank.vhd create mode 100644 vhdl/shifter.vhd create mode 100755 vhdl/simili.cmd create mode 100644 vhdl/spartan3e.ucf create mode 100644 vhdl/tbench.vhd create mode 100644 vhdl/uart.vhd diff --git a/kernel/dll.h b/kernel/dll.h new file mode 100644 index 0000000..4b902c7 --- /dev/null +++ b/kernel/dll.h @@ -0,0 +1,537 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Dynamic Link Library + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 4/4/08 + * FILENAME: dll.h + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Dynamic Link Library + *--------------------------------------------------------------------*/ +#ifndef __DLL_H__ +#define __DLL_H__ + +#define INCLUDE_FILESYS +#include "rtos.h" +#include "tcpip.h" + +typedef void *(*DllFunc)(); + +// Included by Plasma Kernel to create array of function pointers +#ifdef DLL_SETUP + +void *DllDummy(void) { printf("Dummy"); return NULL; } + +const DllFunc DllFuncList[] = { + (DllFunc)strcpy, + (DllFunc)strncpy, + (DllFunc)strcat, + (DllFunc)strncat, + (DllFunc)strcmp, + (DllFunc)strncmp, + (DllFunc)strstr, + (DllFunc)strlen, + (DllFunc)memcpy, + (DllFunc)memmove, + (DllFunc)memcmp, + (DllFunc)memset, + (DllFunc)abs, + (DllFunc)rand, + (DllFunc)srand, + (DllFunc)strtol, + (DllFunc)atoi, + (DllFunc)itoa, + (DllFunc)sprintf, + (DllFunc)sscanf, +#ifdef INCLUDE_DUMP + (DllFunc)dump, +#else //INCLUDE_DUMP + DllDummy, +#endif //INCLUDE_DUMP +#ifdef INCLUDE_QSORT + (DllFunc)qsort, + (DllFunc)bsearch, +#else //INCLUDE_QSORT + DllDummy, + DllDummy, +#endif //INCLUDE_QSORT +#ifdef INCLUDE_TIMELIB + (DllFunc)mktime, + (DllFunc)gmtime_r, + (DllFunc)gmtimeDst, + (DllFunc)gmtimeDstSet, +#else //INCLUDE_TIMELIB + DllDummy, + DllDummy, + DllDummy, + DllDummy, +#endif //INCLUDE_TIMELIB + (DllFunc)OS_AsmInterruptEnable, + (DllFunc)OS_HeapCreate, + (DllFunc)OS_HeapDestroy, + (DllFunc)OS_HeapMalloc, + (DllFunc)OS_HeapFree, + (DllFunc)OS_HeapAlternate, + (DllFunc)OS_HeapRegister, + (DllFunc)OS_ThreadCreate, + (DllFunc)OS_ThreadExit, + (DllFunc)OS_ThreadSelf, + (DllFunc)OS_ThreadSleep, + (DllFunc)OS_ThreadTime, + (DllFunc)OS_ThreadInfoSet, + (DllFunc)OS_ThreadInfoGet, + (DllFunc)OS_ThreadPriorityGet, + (DllFunc)OS_ThreadPrioritySet, + (DllFunc)OS_ThreadProcessId, + (DllFunc)OS_ThreadCpuLock, + (DllFunc)OS_SemaphoreCreate, + (DllFunc)OS_SemaphoreDelete, + (DllFunc)OS_SemaphorePend, + (DllFunc)OS_SemaphorePost, + (DllFunc)OS_MutexCreate, + (DllFunc)OS_MutexDelete, + (DllFunc)OS_MutexPend, + (DllFunc)OS_MutexPost, + (DllFunc)OS_MQueueCreate, + (DllFunc)OS_MQueueDelete, + (DllFunc)OS_MQueueSend, + (DllFunc)OS_MQueueGet, + (DllFunc)OS_Job, + (DllFunc)OS_TimerCreate, + (DllFunc)OS_TimerDelete, + (DllFunc)OS_TimerCallback, + (DllFunc)OS_TimerStart, + (DllFunc)OS_TimerStop, + (DllFunc)OS_InterruptRegister, + (DllFunc)OS_InterruptStatus, + (DllFunc)OS_InterruptMaskSet, + (DllFunc)OS_InterruptMaskClear, + (DllFunc)UartPrintf, + (DllFunc)UartPrintfPoll, + (DllFunc)UartPrintfCritical, + (DllFunc)UartScanf, + (DllFunc)puts, + (DllFunc)getch, + (DllFunc)kbhit, + (DllFunc)Led, + (DllFunc)FP_Sqrt, + (DllFunc)FP_Cos, + (DllFunc)FP_Sin, + (DllFunc)FP_Atan, + (DllFunc)FP_Atan2, + (DllFunc)FP_Exp, + (DllFunc)FP_Log, + (DllFunc)FP_Pow, +#ifdef INCLUDE_FILESYS + (DllFunc)OS_fopen, + (DllFunc)OS_fclose, + (DllFunc)OS_fread, + (DllFunc)OS_fwrite, + (DllFunc)OS_fseek, + (DllFunc)OS_fmkdir, + (DllFunc)OS_fdir, + (DllFunc)OS_fdelete, +#else //INCLUDE_FILESYS + DllDummy, + DllDummy, + DllDummy, + DllDummy, + DllDummy, + DllDummy, + DllDummy, + DllDummy, +#endif //INCLUDE_FILESYS +#ifndef WIN32 + (DllFunc)FlashRead, + (DllFunc)FlashWrite, + (DllFunc)FlashErase, +#else //WIN32 + DllDummy, + DllDummy, + DllDummy, +#endif //WIN32 + (DllFunc)IPOpen, + (DllFunc)IPWriteFlush, + (DllFunc)IPWrite, + (DllFunc)IPRead, + (DllFunc)IPClose, + (DllFunc)IPPrintf, + (DllFunc)IPResolve, + (DllFunc)IPAddressSelf, + (DllFunc)IPNameValue +}; + +#endif //DLL_SETUP + +// Included by DLL to call OS functions via array of function pointers +#if defined(DLL_CALL) || !defined(DLL_SETUP) + +enum { + ENUM_strcpy, + ENUM_strncpy, + ENUM_strcat, + ENUM_strncat, + ENUM_strcmp, + ENUM_strncmp, + ENUM_strstr, + ENUM_strlen, + ENUM_memcpy, + ENUM_memmove, + ENUM_memcmp, + ENUM_memset, + ENUM_abs, + ENUM_rand, + ENUM_srand, + ENUM_strtol, + ENUM_atoi, + ENUM_itoa, + ENUM_sprintf, + ENUM_sscanf, + ENUM_dump, + ENUM_qsort, + ENUM_bsearch, + ENUM_mktime, + ENUM_gmtime_r, + ENUM_gmtimeDst, + ENUM_gmtimeDstSet, + ENUM_OS_AsmInterruptEnable, + ENUM_OS_HeapCreate, + ENUM_OS_HeapDestroy, + ENUM_OS_HeapMalloc, + ENUM_OS_HeapFree, + ENUM_OS_HeapAlternate, + ENUM_OS_HeapRegister, + ENUM_OS_ThreadCreate, + ENUM_OS_ThreadExit, + ENUM_OS_ThreadSelf, + ENUM_OS_ThreadSleep, + ENUM_OS_ThreadTime, + ENUM_OS_ThreadInfoSet, + ENUM_OS_ThreadInfoGet, + ENUM_OS_ThreadPriorityGet, + ENUM_OS_ThreadPrioritySet, + ENUM_OS_ThreadProcessId, + ENUM_OS_ThreadCpuLock, + ENUM_OS_SemaphoreCreate, + ENUM_OS_SemaphoreDelete, + ENUM_OS_SemaphorePend, + ENUM_OS_SemaphorePost, + ENUM_OS_MutexCreate, + ENUM_OS_MutexDelete, + ENUM_OS_MutexPend, + ENUM_OS_MutexPost, + ENUM_OS_MQueueCreate, + ENUM_OS_MQueueDelete, + ENUM_OS_MQueueSend, + ENUM_OS_MQueueGet, + ENUM_OS_Job, + ENUM_OS_TimerCreate, + ENUM_OS_TimerDelete, + ENUM_OS_TimerCallback, + ENUM_OS_TimerStart, + ENUM_OS_TimerStop, + ENUM_OS_InterruptRegister, + ENUM_OS_InterruptStatus, + ENUM_OS_InterruptMaskSet, + ENUM_OS_InterruptMaskClear, + ENUM_UartPrintf, + ENUM_UartPrintfPoll, + ENUM_UartPrintfCritical, + ENUM_UartScanf, + ENUM_puts, + ENUM_getch, + ENUM_kbhit, + ENUM_Led, + ENUM_FP_Sqrt, + ENUM_FP_Cos, + ENUM_FP_Sin, + ENUM_FP_Atan, + ENUM_FP_Atan2, + ENUM_FP_Exp, + ENUM_FP_Log, + ENUM_FP_Pow, + ENUM_OS_fopen, + ENUM_OS_fclose, + ENUM_OS_fread, + ENUM_OS_fwrite, + ENUM_OS_fseek, + ENUM_OS_fmkdir, + ENUM_OS_fdir, + ENUM_OS_fdelete, + ENUM_FlashRead, + ENUM_FlashWrite, + ENUM_FlashErase, + ENUM_IPOpen, + ENUM_IPWriteFlush, + ENUM_IPWrite, + ENUM_IPRead, + ENUM_IPClose, + ENUM_IPPrintf, + ENUM_IPResolve, + ENUM_IPAddressSelf, + ENUM_IPNameValue +}; + +extern const DllFunc *DllF; + +#undef strcpy +#undef strcat +#undef strncat +#undef strcmp +#undef strlen +#undef memcpy +#undef memcmp +#undef memset +#undef abs +#undef atoi +#undef puts +#undef getch +#undef kbhit + +#define strcpy DllF[ENUM_strcpy] +#define strncpy DllF[ENUM_strncpy] +#define strcat DllF[ENUM_strcat] +#define strncat DllF[ENUM_strncat] +#define strcmp (int)DllF[ENUM_strcmp] +#define strncmp (int)DllF[ENUM_strncmp] +#define strstr DllF[ENUM_strstr] +#define strlen (int)DllF[ENUM_strlen] +#define memcpy DllF[ENUM_memcpy] +#define memmove DllF[ENUM_memmove] +#define memcmp (int)DllF[ENUM_memcmp] +#define memset DllF[ENUM_memset] +#define abs (int)DllF[ENUM_abs] +#define rand (int)DllF[ENUM_rand] +#define srand DllF[ENUM_srand] +#define strtol (int)DllF[ENUM_strtol] +#define atoi (int)DllF[ENUM_atoi] +#define itoa DllF[ENUM_itoa] +#define sprintf DllF[ENUM_sprintf] +#define sscanf DllF[ENUM_sscanf] +#define dump DllF[ENUM_dump] +#define qsort DllF[ENUM_qsort] +#define bsearch DllF[ENUM_bsearch] +#define mktime DllF[ENUM_mktime] +#define gmtime_r DllF[ENUM_gmtime_r] +#define gmtimeDst DllF[ENUM_gmtimeDst] +#define gmtimeDstSet DllF[ENUM_gmtimeDstSet] +#define OS_AsmInterruptEnable (int)DllF[ENUM_OS_AsmInterruptEnable] +#define OS_HeapCreate DllF[ENUM_OS_HeapCreate] +#define OS_HeapDestroy DllF[ENUM_OS_HeapDestroy] +#define OS_HeapMalloc DllF[ENUM_OS_HeapMalloc] +#define OS_HeapFree DllF[ENUM_OS_HeapFree] +#define OS_HeapAlternate DllF[ENUM_OS_HeapAlternate] +#define OS_HeapRegister DllF[ENUM_OS_HeapRegister] +#define OS_ThreadCreate DllF[ENUM_OS_ThreadCreate] +#define OS_ThreadExit DllF[ENUM_OS_ThreadExit] +#define OS_ThreadSelf DllF[ENUM_OS_ThreadSelf] +#define OS_ThreadSleep DllF[ENUM_OS_ThreadSleep] +#define OS_ThreadTime DllF[ENUM_OS_ThreadTime] +#define OS_ThreadInfoSet DllF[ENUM_OS_ThreadInfoSet] +#define OS_ThreadInfoGet DllF[ENUM_OS_ThreadInfoGet] +#define OS_ThreadPriorityGet (int)DllF[ENUM_OS_ThreadPriorityGet] +#define OS_ThreadPrioritySet DllF[ENUM_OS_ThreadPrioritySet] +#define OS_ThreadProcessId DllF[ENUM_OS_ThreadProcessId] +#define OS_ThreadCpuLock DllF[ENUM_OS_ThreadCpuLock] +#define OS_SemaphoreCreate DllF[ENUM_OS_SemaphoreCreate] +#define OS_SemaphoreDelete DllF[ENUM_OS_SemaphoreDelete] +#define OS_SemaphorePend (int)DllF[ENUM_OS_SemaphorePend] +#define OS_SemaphorePost DllF[ENUM_OS_SemaphorePost] +#define OS_MutexCreate DllF[ENUM_OS_MutexCreate] +#define OS_MutexDelete DllF[ENUM_OS_MutexDelete] +#define OS_MutexPend (int)DllF[ENUM_OS_MutexPend] +#define OS_MutexPost DllF[ENUM_OS_MutexPost] +#define OS_MQueueCreate DllF[ENUM_OS_MQueueCreate] +#define OS_MQueueDelete DllF[ENUM_OS_MQueueDelete] +#define OS_MQueueSend DllF[ENUM_OS_MQueueSend] +#define OS_MQueueGet (int)DllF[ENUM_OS_MQueueGet] +#define OS_Job DllF[ENUM_OS_Job] +#define OS_TimerCreate DllF[ENUM_OS_TimerCreate] +#define OS_TimerDelete DllF[ENUM_OS_TimerDelete] +#define OS_TimerCallback DllF[ENUM_OS_TimerCallback] +#define OS_TimerStart DllF[ENUM_OS_TimerStart] +#define OS_TimerStop DllF[ENUM_OS_TimerStop] +#define OS_InterruptRegister DllF[ENUM_OS_InterruptRegister] +#define OS_InterruptStatus (int)DllF[ENUM_OS_InterruptStatus] +#define OS_InterruptMaskSet DllF[ENUM_OS_InterruptMaskSet] +#define OS_InterruptMaskClear DllF[ENUM_OS_InterruptMaskClear] +#define UartPrintf DllF[ENUM_UartPrintf] +#define UartPrintfPoll DllF[ENUM_UartPrintfPoll] +#define UartPrintfCritical DllF[ENUM_UartPrintfCritical] +#define UartScanf DllF[ENUM_UartScanf] +#define puts DllF[ENUM_puts] +#define getch (int)DllF[ENUM_getch] +#define kbhit (int)DllF[ENUM_kbhit] +#define Led DllF[ENUM_Led] +#define FP_Sqrt (float)(int)DllF[ENUM_FP_Sqrt] +#define FP_Cos (float)(int)DllF[ENUM_FP_Cos] +#define FP_Sin (float)(int)DllF[ENUM_FP_Sin] +#define FP_Atan (float)(int)DllF[ENUM_FP_Atan] +#define FP_Atan2 (float)(int)DllF[ENUM_FP_Atan2] +#define FP_Exp (float)(int)DllF[ENUM_FP_Exp] +#define FP_Log (float)(int)DllF[ENUM_FP_Log] +#define FP_Pow (float)(int)DllF[ENUM_FP_Pow] +#define OS_fopen DllF[ENUM_OS_fopen] +#define OS_fclose DllF[ENUM_OS_fclose] +#define OS_fread (int)DllF[ENUM_OS_fread] +#define OS_fwrite DllF[ENUM_OS_fwrite] +#define OS_fseek DllF[ENUM_OS_fseek] +#define OS_fmkdir DllF[ENUM_OS_fmkdir] +#define OS_fdir DllF[ENUM_OS_fdir] +#define OS_fdelete DllF[ENUM_OS_fdelete] +#define FlashRead DllF[ENUM_FlashRead] +#define FlashWrite DllF[ENUM_FlashWrite] +#define FlashErase DllF[ENUM_FlashErase] +#define IPOpen DllF[ENUM_IPOpen] +#define IPWriteFlush DllF[ENUM_IPWriteFlush] +#define IPWrite (int)DllF[ENUM_IPWrite] +#define IPRead (int)DllF[ENUM_IPRead] +#define IPClose DllF[ENUM_IPClose] +#define IPPrintf DllF[ENUM_IPPrintf] +#define IPResolve DllF[ENUM_IPResolve] +#define IPAddressSelf (int)DllF[ENUM_IPAddressSelf] +#define IPNameValue DllF[ENUM_IPNameValue] + +#endif //DLL_CALL + + +#if defined(DLL_SETUP) && defined(DLL_CALL) +const DllFunc *DllF = DllFuncList; +#elif !defined(DLL_SETUP) && !defined(DLL_CALL) && !defined(DLL_ENTRY) +#define DLL_ENTRY 1 +#endif //DLL_SETUP && DLL_CALL + + +// Included by DLL to initialize the DLL +#if defined(DLL_ENTRY) && !defined(NO_DLL_ENTRY) +const DllFunc *DllF; //array of function pointers +extern void *__bss_start; +extern void *_end; +void Start(IPSocket *socket, char *argv[]); + +//Must be first function in file +void *__start(DllFunc *DllFuncList) +{ + int *bss; + if(DllFuncList == NULL) + return (void*)__start; //address where DLL should be loaded + for(bss = (int*)&__bss_start; bss < (int*)&_end; ++bss) + *bss = 0; + DllF = DllFuncList; + return (void*)Start; +} +#endif //DLL_ENTRY + + +#ifdef DLL_STRINGS +const char * const DllStrings[] = { + "strcpy", + "strncpy", + "strcat", + "strncat", + "strcmp", + "strncmp", + "strstr", + "strlen", + "memcpy", + "memmove", + "memcmp", + "memset", + "abs", + "rand", + "srand", + "strtol", + "atoi", + "itoa", + "sprintf", + "sscanf", + "dump", + "qsort", + "bsearch", + "mktime", + "gmtime_r", + "gmtimeDst", + "gmtimeDstSet", + "OS_AsmInterruptEnable", + "OS_HeapCreate", + "OS_HeapDestroy", + "OS_HeapMalloc", + "OS_HeapFree", + "OS_HeapAlternate", + "OS_HeapRegister", + "OS_ThreadCreate", + "OS_ThreadExit", + "OS_ThreadSelf", + "OS_ThreadSleep", + "OS_ThreadTime", + "OS_ThreadInfoSet", + "OS_ThreadInfoGet", + "OS_ThreadPriorityGet", + "OS_ThreadPrioritySet", + "OS_ThreadProcessId", + "OS_ThreadCpuLock", + "OS_SemaphoreCreate", + "OS_SemaphoreDelete", + "OS_SemaphorePend", + "OS_SemaphorePost", + "OS_MutexCreate", + "OS_MutexDelete", + "OS_MutexPend", + "OS_MutexPost", + "OS_MQueueCreate", + "OS_MQueueDelete", + "OS_MQueueSend", + "OS_MQueueGet", + "OS_Job", + "OS_TimerCreate", + "OS_TimerDelete", + "OS_TimerCallback", + "OS_TimerStart", + "OS_TimerStop", + "OS_InterruptRegister", + "OS_InterruptStatus", + "OS_InterruptMaskSet", + "OS_InterruptMaskClear", + "printf", //"UartPrintf", + "UartPrintfPoll", + "UartPrintfCritical", + "scanf", //"UartScanf", + "puts", + "getch", + "kbhit", + "Led", + "FP_Sqrt", + "FP_Cos", + "FP_Sin", + "FP_Atan", + "FP_Atan2", + "FP_Exp", + "FP_Log", + "FP_Pow", + "OS_fopen", + "OS_fclose", + "OS_fread", + "OS_fwrite", + "OS_fseek", + "OS_fmkdir", + "OS_fdir", + "OS_fdelete", + "FlashRead", + "FlashWrite", + "FlashErase", + "IPOpen", + "IPWriteFlush", + "IPWrite", + "IPRead", + "IPClose", + "IPPrintf", + "IPResolve", + "IPAddressSelf", + "IPNameValue", + NULL +}; +#endif //DLL_STRINGS + +#endif //__DLL_H__ + diff --git a/kernel/dlltest.c b/kernel/dlltest.c new file mode 100644 index 0000000..12a4390 --- /dev/null +++ b/kernel/dlltest.c @@ -0,0 +1,38 @@ +// dlltest.c +// Compile this program with "make dlltest". +// Then ftp test.bin to /flash/bin/dlltest. +// Then from a telnet prompt type "dlltest". +#include "dll.h" + + +void SocketReceive(IPSocket *socket) +{ +} + + +void MyThread(void *sock) +{ + char buf[80]; + int i, bytes; + IPSocket *socket = sock; + + for(i = 0; i < 10; ++i) + { + bytes = IPRead(socket, buf, sizeof(buf)-1); + buf[bytes] = 0; + IPPrintf(socket, "%d %s\n", i, buf); + OS_ThreadSleep(100); + } + socket->funcPtr = socket->userFunc; //restore socket receive function +} + + +// Function shouldn't block +void Start(IPSocket *socket, char *argv[]) +{ + IPPrintf(socket, "Hello from dlltest\n"); + socket->userFunc = socket->funcPtr; //remember prev socket receive func + socket->funcPtr = SocketReceive; //new socket receive function + OS_ThreadCreate("MyThread", MyThread, socket, 100, 0); +} + diff --git a/kernel/ethernet.c b/kernel/ethernet.c new file mode 100644 index 0000000..752b55d --- /dev/null +++ b/kernel/ethernet.c @@ -0,0 +1,428 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Ethernet MAC + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 1/12/08 + * FILENAME: ethernet.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Ethernet MAC implementation. + * Data is received from the Ethernet PHY four bits at a time. + * After 32-bits are received they are written to 0x13ff0000 + N. + * The data is received LSB first for each byte which requires the + * nibbles to be swapped. + * Transmit data is read from 0x13fe0000. Write length/4+1 to + * ETHERNET_REG to start transfer. + *--------------------------------------------------------------------*/ +#include "plasma.h" +#include "rtos.h" +#include "tcpip.h" + +#define POLYNOMIAL 0x04C11DB7 //CRC bit 33 is truncated +#define TOPBIT (1<<31) +#define BYTE_EMPTY 0xde //Data copied into receive buffer +#define COUNT_EMPTY 16 //Count to decide there isn't data +#define INDEX_MASK 0xffff //Size of receive buffer + +//void dump(const unsigned char *data, int length); + +static unsigned char gDestMac[]={0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static unsigned int CrcTable[256]; +static unsigned char reflect[256]; +static unsigned char reflectNibble[256]; +static OS_Semaphore_t *SemEthernet, *SemEthTransmit; +static int gIndex; //byte index into 0x13ff0000 receive buffer +static int gCheckedBefore; +static int gEmptyBefore; + + +//Read received data from 0x13ff0000. Data starts with 0x5d+MACaddress. +//Data is being received while processing the data. Therefore, +//all errors require waiting and then re-processing the data +//to see if the error is fixed by receiving the rest of the packet. +int EthernetReceive(unsigned char *buffer, int length) +{ + int count; + int start, i, j, shift, offset; + int byte, byteNext; + unsigned long crc; + int byteCrc; + volatile unsigned char *buf = (unsigned char*)ETHERNET_RECEIVE; + int countEmpty, countEmptyGoal, countOk, needWait; + int packetExpected; + + //Find the start of a frame + countEmpty = 0; + countOk = 0; + needWait = 0; + countEmptyGoal = COUNT_EMPTY; + packetExpected = MemoryRead(IRQ_STATUS) & IRQ_ETHERNET_RECEIVE; + if(packetExpected && buf[gIndex] == BYTE_EMPTY && gEmptyBefore) + { + //printf("Check "); + countEmptyGoal = 1500; + } + MemoryRead(ETHERNET_REG); //clear receive interrupt + for(i = 0; i < INDEX_MASK; ++i) + { + //Check if partial packet possibly received + if(needWait && gCheckedBefore == 0 && countOk != i && countEmpty != i) + { + gCheckedBefore = 1; + //printf("W(%d,%d,%d)", i, countOk, countEmpty); + return 0; //Wait for more data + } + + //Detect start of frame + byte = buf[(gIndex + i) & INDEX_MASK]; + if(byte == gDestMac[countOk] || (countOk && byte == 0xff)) + { + if(++countOk == sizeof(gDestMac)) + { + //Set bytes before 0x5d to BYTE_EMPTY + offset = i - (int)sizeof(gDestMac); + //if(offset > 3) + // printf("es%d ", offset); + for(j = 0; j <= offset; ++j) + { + buf[gIndex] = BYTE_EMPTY; + gIndex = (gIndex + 1) & INDEX_MASK; + } + break; + } + } + else + { + //if(countOk) + // printf("N%d ", countOk); + if(countOk == 3 && byte == BYTE_EMPTY) + needWait = 1; + if(byte == 0x5d) + countOk = 1; + else + countOk = 0; + } + + //Check if remainder of buffer is empty + if(byte == BYTE_EMPTY) + { + if(++countEmpty >= countEmptyGoal) + { + //Set skiped bytes to BYTE_EMPTY + //if(i - countEmpty > 3) + //{ + // printf("eb%d \n", i - countEmpty); + // //dump((char*)buf+gIndex, 0x200); + //} + for(j = 0; j <= i - countEmpty; ++j) + { + buf[gIndex] = BYTE_EMPTY; + gIndex = (gIndex + 1) & INDEX_MASK; + } + gCheckedBefore = 0; + if(countEmpty >= i && packetExpected) + gEmptyBefore = 1; + return 0; + } + } + else + { + if(countEmpty > 2 || (countEmpty > 0 && countEmpty == i)) + needWait = 1; + countEmpty = 0; + gEmptyBefore = 0; + } + } + + //Found start of frame. Now find end of frame and check CRC. + start = gIndex; + gIndex = (gIndex + 1) & INDEX_MASK; //skip 0x5d byte + crc = 0xffffffff; + for(count = 0; count < length; ) + { + byte = buf[gIndex]; + gIndex = (gIndex + 1) & INDEX_MASK; + + byte = ((byte << 4) & 0xf0) | (byte >> 4); //swap nibbles + buffer[count++] = (unsigned char)byte; + byte = reflect[byte] ^ (crc >> 24); //calculate CRC32 + crc = CrcTable[byte] ^ (crc << 8); + if(count >= 40) + { + //Check if CRC matches to detect end of frame + byteCrc = reflectNibble[crc >> 24]; + byteNext = buf[gIndex]; + if(byteCrc == byteNext) + { + for(i = 1; i < 4; ++i) + { + shift = 24 - (i << 3); + byteCrc = reflectNibble[(crc >> shift) & 0xff]; + byteNext = buf[(gIndex + i) & 0xffff]; + if(byteCrc != byteNext) + { + //printf("nope %d %d 0x%x 0x%x\n", count, i, byteCrc, byteNext); + i = 99; + } + } + if(i == 4) + { + //Found end of frame -- set used bytes to BYTE_EMPTY + //printf("Found it! %d\n", count); + gIndex = (gIndex + 4) & INDEX_MASK; + for(i = 0; i < count+5; ++i) + buf[(start + i) & INDEX_MASK] = BYTE_EMPTY; + while(gIndex & 3) + { + buf[gIndex] = BYTE_EMPTY; + gIndex = (gIndex + 1) & INDEX_MASK; + } + gCheckedBefore = 0; + return count; + } + } + } + } + gIndex = start; + if(gCheckedBefore) + { + //printf("CRC failure\n"); + buf[gIndex] = BYTE_EMPTY; + } + gCheckedBefore = 1; + return 0; //wait for more data +} + + +//Copy transmit data to 0x13fe0000 with preamble and CRC32 +void EthernetTransmit(unsigned char *buffer, int length) +{ + int i, byte, shift; + unsigned long crc; + volatile unsigned char *buf = (unsigned char*)ETHERNET_TRANSMIT; + + OS_SemaphorePend(SemEthTransmit, OS_WAIT_FOREVER); + + //Wait for previous transfer to complete + for(i = 0; i < 10000; ++i) + { + if(MemoryRead(IRQ_STATUS) & IRQ_ETHERNET_TRANSMIT) + break; + } + //if(i > 100) + // printf("wait=%d ", i); + + Led(2, 2); + while(length < 60 || (length & 3) != 0) + buffer[length++] = 0; + + //Start of Ethernet frame + for(i = 0; i < 7; ++i) + buf[i] = 0x55; + buf[7] = 0x5d; + + //Calculate CRC32 + crc = 0xffffffff; + for(i = 0; i < length; ++i) + { + byte = buffer[i]; + buf[i + 8] = (unsigned char)((byte << 4) | (byte >> 4)); //swap nibbles + byte = reflect[byte] ^ (crc >> 24); //calculate CRC32 + crc = CrcTable[byte] ^ (crc << 8); + } + + //Output CRC32 + for(i = 0; i < 4; ++i) + { + shift = 24 - (i << 3); + byte = reflectNibble[(crc >> shift) & 0xff]; + buf[length + 8 + i] = (unsigned char)byte; + } + + //Start transfer + length = (length + 12 + 4) >> 2; + MemoryWrite(ETHERNET_REG, length); + Led(2, 0); + + OS_SemaphorePost(SemEthTransmit); +} + + +void EthernetThread(void *arg) +{ + int length; + int rc; + unsigned int ticks, ticksLast=0; + IPFrame *ethFrame=NULL; + static int ethErrorCount=0; + (void)arg; + + for(;;) + { + OS_InterruptMaskSet(IRQ_ETHERNET_RECEIVE); + OS_SemaphorePend(SemEthernet, 50); //wait for interrupt + + //Process all received packets + for(;;) + { + if(ethFrame == NULL) + ethFrame = IPFrameGet(FRAME_COUNT_RCV); + if(ethFrame == NULL) + { + OS_ThreadSleep(50); + break; + } + length = EthernetReceive(ethFrame->packet, PACKET_SIZE); + if(length == 0) + { +#if 1 //Disable this on quiet networks + //No Ethernet packets seen for 60 seconds? + if(++ethErrorCount >= 120) + { + printf("\nEthernetInit\n"); + ethErrorCount = 0; + EthernetInit(NULL); //Need to re-initialize + } +#endif + break; + } + ethErrorCount = 0; + Led(1, 1); + rc = IPProcessEthernetPacket(ethFrame, length); + Led(1, 0); + if(rc) + ethFrame = NULL; + } + + ticks = OS_ThreadTime(); + if(ticks - ticksLast >= 50) + { + IPTick(); + ticksLast = ticks; + } + } +} + + +void EthernetIsr(void *arg) +{ + (void)arg; + OS_InterruptMaskClear(IRQ_ETHERNET_TRANSMIT | IRQ_ETHERNET_RECEIVE); + OS_SemaphorePost(SemEthernet); +} + + +/******************* CRC32 calculations ********************** + * The CRC32 code is modified from Michale Barr's article in + * Embedded Systems Programming January 2000. + * A CRC is really modulo-2 binary division. Substraction means XOR. */ +static unsigned int Reflect(unsigned int value, int bits) +{ + unsigned int num=0; + int i; + for(i = 0; i < bits; ++i) + { + num = (num << 1) | (value & 1); + value >>= 1; + } + return num; +} + + +static void CrcInit(void) +{ + unsigned int remainder; + int dividend, bit, i; + + //Compute the remainder of each possible dividend + for(dividend = 0; dividend < 256; ++dividend) + { + //Start with the dividend followed by zeros + remainder = dividend << 24; + //Perform modulo-2 division, a bit at a time + for(bit = 8; bit > 0; --bit) + { + //Try to divide the current data bit + if(remainder & TOPBIT) + remainder = (remainder << 1) ^ POLYNOMIAL; + else + remainder = remainder << 1; + } + CrcTable[dividend] = remainder; + } + for(i = 0; i < 256; ++i) + { + reflect[i] = (unsigned char)Reflect(i, 8); + reflectNibble[i] = (unsigned char)((Reflect((i >> 4) ^ 0xf, 4) << 4) | + Reflect(i ^ 0xf, 4)); + } +} + + +static void SpinWait(int clocks) +{ + int value = *(volatile int*)COUNTER_REG + clocks; + while(*(volatile int*)COUNTER_REG - value < 0) + ; +} + + +void EthernetInit(unsigned char MacAddress[6]) +{ + //Format of SMI data: 0101 A4:A0 R4:R0 00 D15:D0 + unsigned long data=0x5f800100; //SMI R0 = 10Mbps full duplex + //unsigned long data=0x5f800000; //SMI R0 = 10Mbps half duplex + int i, value; + volatile unsigned char *buf = (unsigned char*)ETHERNET_RECEIVE; + + CrcInit(); + if(MacAddress) + { + for(i = 0; i < 6; ++i) + { + value = MacAddress[i]; + gDestMac[i+1] = (unsigned char)((value >> 4) | (value << 4)); + } + } + + //Configure Ethernet PHY for 10Mbps full duplex via SMI interface + MemoryWrite(GPIO0_OUT, ETHERNET_MDIO | ETHERNET_MDIO_WE | ETHERENT_MDC); + for(i = 0; i < 34; ++i) + { + MemoryWrite(GPIO0_OUT, ETHERENT_MDC); //clock high + SpinWait(10); + MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC); //clock low + SpinWait(10); + } + for(i = 31; i >= 0; --i) + { + value = (data >> i) & 1; + if(value) + MemoryWrite(GPIO0_OUT, ETHERNET_MDIO); + else + MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO); + MemoryWrite(GPIO0_OUT, ETHERENT_MDC); //clock high + SpinWait(10); + MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC); //clock low + SpinWait(10); + } + MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO_WE | ETHERNET_ENABLE); + + //Clear receive buffer + for(i = 0; i <= INDEX_MASK; ++i) + buf[i] = BYTE_EMPTY; + + if(SemEthernet == NULL) + { + SemEthernet = OS_SemaphoreCreate("eth", 0); + SemEthTransmit = OS_SemaphoreCreate("ethT", 1); + OS_ThreadCreate("eth", EthernetThread, NULL, 240, 0); + } + + //Setup interrupts for receiving data + OS_InterruptRegister(IRQ_ETHERNET_RECEIVE, EthernetIsr); + + //Start receive DMA + MemoryWrite(GPIO0_OUT, ETHERNET_ENABLE); +} diff --git a/kernel/filesys.c b/kernel/filesys.c new file mode 100644 index 0000000..eefdf97 --- /dev/null +++ b/kernel/filesys.c @@ -0,0 +1,767 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma File System + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 4/26/07 + * FILENAME: filesys.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma File System. Supports RAM, flash, and disk file systems. + * Possible call tree: + * OS_fclose() + * FileFindRecursive() //find the existing file + * FileOpen() //open root file system + * FileFind() //find the next level of directory + * OS_fread() //read the directory file + * BlockRead() //read blocks of directory + * MediaBlockRead() //low level read + * FileOpen() //open next directory + * OS_fwrite() //write file entry into directory + * BlockRead() //flush changes to directory + *--------------------------------------------------------------------*/ +#ifdef WIN32 +#include +#include +#include +#define _LIBC +#endif +#include "rtos.h" + +#define FLASH_SIZE 1024*1024*16 +#define FLASH_SECTOR_SIZE 1024*128 +#define FLASH_BLOCK_SIZE 512 +#define FLASH_LN2_SIZE 9 //2^FLASH_LN2_SIZE == FLASH_BLOCK_SIZE +#define FLASH_OFFSET FLASH_SECTOR_SIZE //offset to start of flash file system + +#define BLOCK_SIZE 512 +#define FILE_NAME_SIZE 40 +#define FULL_NAME_SIZE 128 +#define BLOCK_MALLOC 0x0 +#define BLOCK_EOF 0xffffffff + +typedef enum { + FILE_MEDIA_RAM, + FILE_MEDIA_FLASH, + FILE_MEDIA_DISK +} OS_MediaType_e; + +typedef struct OS_FileEntry_s { + char name[FILE_NAME_SIZE]; + uint32 blockIndex; //first block of file + uint32 modifiedTime; + uint32 length; + uint8 isDirectory; + uint8 attributes; + uint8 valid; + uint8 mediaType; + uint16 blockSize; //Normally BLOCK_SIZE +} OS_FileEntry_t; + +typedef struct OS_Block_s { + uint32 next; + uint8 data[4]; +} OS_Block_t; + +struct OS_FILE_s { + OS_FileEntry_t fileEntry; //written to directory upon OS_fclose() + uint8 fileModified; + uint8 blockModified; + uint32 blockIndex; //index of block + uint32 blockOffset; //byte offset into block + uint32 fileOffset; //byte offset into file + char fullname[FULL_NAME_SIZE]; //includes full path + OS_Block_t *block; + OS_Block_t *blockLocal; //local copy for flash or disk file system +}; + +static OS_FileEntry_t rootFileEntry; +static OS_Mutex_t *mutexFilesys; + +// Public prototypes +#ifndef _FILESYS_ +typedef struct OS_FILE_s OS_FILE; +#endif +OS_FILE *OS_fopen(char *name, char *mode); +void OS_fclose(OS_FILE *file); +int OS_fread(void *buffer, int size, int count, OS_FILE *file); +int OS_fwrite(void *buffer, int size, int count, OS_FILE *file); +int OS_fseek(OS_FILE *file, int offset, int mode); +int OS_fmkdir(char *name); +int OS_fdir(OS_FILE *dir, char name[64]); +void OS_fdelete(char *name); + + +/***************** Media Functions Start ***********************/ +#ifdef INCLUDE_FLASH +#define FLASH_BLOCKS FLASH_SIZE/FLASH_BLOCK_SIZE +#define FLASH_START (FLASH_OFFSET+FLASH_BLOCKS/8*2)/FLASH_BLOCK_SIZE +static unsigned char FlashBlockEmpty[FLASH_BLOCKS/8]; +static unsigned char FlashBlockUsed[FLASH_BLOCKS/8]; +static int FlashBlock; + +//Free unused flash blocks +static int MediaBlockCleanup(void) +{ + int i, sector, block, count=0; + unsigned char *buf; + + printf("FlashCleanup\n"); + buf = (unsigned char*)malloc(FLASH_SECTOR_SIZE); + if(buf == NULL) + return 0; + for(sector = FLASH_OFFSET / FLASH_SECTOR_SIZE; sector < FLASH_SIZE / FLASH_SECTOR_SIZE; ++sector) + { + FlashRead((uint16*)buf, FLASH_SECTOR_SIZE*sector, FLASH_SECTOR_SIZE); + if(sector == FLASH_OFFSET / FLASH_SECTOR_SIZE) + { + for(i = 0; i < FLASH_BLOCKS/8; ++i) + FlashBlockEmpty[i] |= ~FlashBlockUsed[i]; + memcpy(buf, FlashBlockEmpty, sizeof(FlashBlockEmpty)); + memset(FlashBlockUsed, 0xff, sizeof(FlashBlockUsed)); + memset(buf+sizeof(FlashBlockEmpty), 0xff, sizeof(FlashBlockUsed)); + } + //Erase empty blocks + for(block = 0; block < FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE; ++block) + { + i = sector * FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE + block; + if(i < FLASH_BLOCKS/8 && (FlashBlockEmpty[i >> 3] & (1 << (i & 7)))) + { + memset(buf + FLASH_BLOCK_SIZE*block, 0xff, FLASH_BLOCK_SIZE); + ++count; + } + } + FlashErase(FLASH_SECTOR_SIZE * sector); + FlashWrite((uint16*)buf, FLASH_SECTOR_SIZE * sector, FLASH_SECTOR_SIZE); + } + free(buf); + return count; +} + + +int MediaBlockInit(void) +{ + FlashRead((uint16*)FlashBlockEmpty, FLASH_OFFSET, sizeof(FlashBlockEmpty)); + FlashRead((uint16*)FlashBlockUsed, FLASH_OFFSET+sizeof(FlashBlockEmpty), + sizeof(FlashBlockUsed)); + FlashBlock = FLASH_START; + return FlashBlockEmpty[FlashBlock >> 3] & (1 << (FlashBlock & 7)); +} +#endif + + +static uint32 MediaBlockMalloc(OS_FILE *file) +{ + int i, j; + (void)i; (void)j; + + if(file->fileEntry.mediaType == FILE_MEDIA_RAM) + return (uint32)malloc(file->fileEntry.blockSize); +#ifdef INCLUDE_FLASH + //Find empty flash block + for(i = FlashBlock; i < FLASH_BLOCKS; ++i) + { + if(FlashBlockEmpty[i >> 3] & (1 << (i & 7))) + { + FlashBlock = i + 1; + FlashBlockEmpty[i >> 3] &= ~(1 << (i & 7)); + j = i >> 3; + j &= ~1; + FlashWrite((uint16*)(FlashBlockEmpty + j), FLASH_OFFSET + j, 2); + return i; + } + } + + i = MediaBlockCleanup(); + if(i == 0) + return 0; + FlashBlock = FLASH_START; + return MediaBlockMalloc(file); +#else + return 0; +#endif +} + + +static void MediaBlockFree(OS_FILE *file, uint32 blockIndex) +{ + if(file->fileEntry.mediaType == FILE_MEDIA_RAM) + free((void*)blockIndex); +#ifdef INCLUDE_FLASH + else + { + int i=blockIndex, j; + FlashBlockUsed[i >> 3] &= ~(1 << (i & 7)); + j = i >> 3; + j &= ~1; + FlashWrite((uint16*)(FlashBlockUsed + j), FLASH_OFFSET + sizeof(FlashBlockEmpty) + j, 2); + } +#endif +} + + +static void MediaBlockRead(OS_FILE *file, uint32 blockIndex) +{ + if(file->fileEntry.mediaType == FILE_MEDIA_RAM) + file->block = (OS_Block_t*)blockIndex; +#ifdef INCLUDE_FLASH + else + { + if(file->blockLocal == NULL) + file->blockLocal = (OS_Block_t*)malloc(FLASH_BLOCK_SIZE); + file->block = file->blockLocal; + FlashRead((uint16*)file->block, blockIndex << FLASH_LN2_SIZE, FLASH_BLOCK_SIZE); + } +#endif +} + + +static void MediaBlockWrite(OS_FILE *file, uint32 blockIndex) +{ + (void)file; + (void)blockIndex; +#ifdef INCLUDE_FLASH + if(file->fileEntry.mediaType != FILE_MEDIA_RAM) + FlashWrite((uint16*)file->block, blockIndex << FLASH_LN2_SIZE, FLASH_BLOCK_SIZE); +#endif +} + +/***************** Media Functions End *************************/ + +// Get the next block and write the old block if it was modified +static void BlockRead(OS_FILE *file, uint32 blockIndex) +{ + uint32 blockIndexSave = blockIndex; + + OS_MutexPend(mutexFilesys); + if(blockIndex == BLOCK_MALLOC) + { + // Get a new block + blockIndex = MediaBlockMalloc(file); + if(blockIndex == 0) + blockIndex = BLOCK_EOF; + if(file->block) + { + // Set next pointer in previous block + file->block->next = blockIndex; + file->blockModified = 1; + } + } + if(file->block && file->blockModified) + { + // Write block back to flash or disk + MediaBlockWrite(file, file->blockIndex); + file->blockModified = 0; + } + if(blockIndex == BLOCK_EOF) + { + OS_MutexPost(mutexFilesys); + return; + } + file->blockIndex = blockIndex; + file->blockOffset = 0; + MediaBlockRead(file, blockIndex); + if(blockIndexSave == BLOCK_MALLOC) + { + memset(file->block, 0xff, file->fileEntry.blockSize); + file->blockModified = 1; + } + OS_MutexPost(mutexFilesys); +} + + +int OS_fread(void *buffer, int size, int count, OS_FILE *file) +{ + int items, bytes; + uint8 *buf = (uint8*)buffer; + + for(items = 0; items < count; ++items) + { + for(bytes = 0; bytes < size; ++bytes) + { + if(file->fileOffset >= file->fileEntry.length && + file->fileEntry.isDirectory == 0) + return items; + if(file->blockOffset >= file->fileEntry.blockSize - sizeof(uint32)) + { + if(file->block->next == BLOCK_EOF) + return items; + BlockRead(file, file->block->next); + } + *buf++ = file->block->data[file->blockOffset++]; + ++file->fileOffset; + } + } + return items; +} + + +int OS_fwrite(void *buffer, int size, int count, OS_FILE *file) +{ + int items, bytes; + uint8 *buf = (uint8*)buffer; + + OS_MutexPend(mutexFilesys); + file->blockModified = 1; + for(items = 0; items < count; ++items) + { + for(bytes = 0; bytes < size; ++bytes) + { + if(file->blockOffset >= file->fileEntry.blockSize - sizeof(uint32)) + { + if(file->block->next == BLOCK_EOF) + file->block->next = BLOCK_MALLOC; + BlockRead(file, file->block->next); + if(file->blockIndex == BLOCK_EOF) + { + count = 0; + --items; + break; + } + file->blockModified = 1; + } + file->block->data[file->blockOffset++] = *buf++; + ++file->fileOffset; + } + } + file->blockModified = 1; + file->fileModified = 1; + if(file->fileOffset > file->fileEntry.length) + file->fileEntry.length = file->fileOffset; + OS_MutexPost(mutexFilesys); + return items; +} + + +int OS_fseek(OS_FILE *file, int offset, int mode) +{ + if(mode == 1) //SEEK_CUR + offset += file->fileOffset; + else if(mode == 2) //SEEK_END + offset += file->fileEntry.length; + file->fileOffset = offset; + BlockRead(file, file->fileEntry.blockIndex); + while(offset > (int)file->fileEntry.blockSize - (int)sizeof(uint32)) + { + BlockRead(file, file->block->next); + offset -= file->fileEntry.blockSize - (int)sizeof(uint32); + } + file->blockOffset = offset; + return 0; +} + + +static int FileOpen(OS_FILE *file, char *name, OS_FileEntry_t *fileEntry) +{ + memset(file, 0, sizeof(OS_FILE)); + if(fileEntry == NULL) + { + // Open root file + memcpy(&file->fileEntry, &rootFileEntry, sizeof(OS_FileEntry_t)); + } + else if(fileEntry->valid == 1) + { + // Open existing file + memcpy(&file->fileEntry, fileEntry, sizeof(OS_FileEntry_t)); + } + else + { + // Initialize new file + file->fileModified = 1; + file->blockModified = 1; + memset(&file->fileEntry, 0, sizeof(OS_FileEntry_t)); + file->fileEntry.isDirectory = 0; + file->fileEntry.length = 0; + strncpy(file->fileEntry.name, name, FILE_NAME_SIZE-1); + file->fileEntry.blockIndex = 0; + file->fileEntry.valid = 1; + file->fileEntry.blockSize = fileEntry->blockSize; + file->fileEntry.mediaType = fileEntry->mediaType; + } + BlockRead(file, file->fileEntry.blockIndex); //Get first block + file->fileEntry.blockIndex = file->blockIndex; + file->fileOffset = 0; + if(file->blockIndex == BLOCK_EOF) + return -1; + return 0; +} + + +static int FileFind(OS_FILE *directory, char *name, OS_FileEntry_t *fileEntry) +{ + int count, rc = -1; + uint32 blockIndex, blockOffset; + uint32 blockIndexEmpty=BLOCK_EOF, blockOffsetEmpty=0; + + // Loop through files in directory + for(;;) + { + blockIndex = directory->blockIndex; + blockOffset = directory->blockOffset; + count = OS_fread(fileEntry, sizeof(OS_FileEntry_t), 1, directory); + if(count == 0 || fileEntry->blockIndex == BLOCK_EOF) + break; + if(fileEntry->valid == 1 && strcmp(fileEntry->name, name) == 0) + { + rc = 0; //Found the file in the directory + break; + } + if(fileEntry->valid != 1 && blockIndexEmpty == BLOCK_EOF) + { + blockIndexEmpty = blockIndex; + blockOffsetEmpty = blockOffset; + } + } + if(rc == 0 || directory->fileEntry.mediaType == FILE_MEDIA_FLASH || + blockIndexEmpty == BLOCK_EOF) + { + // Backup to start of fileEntry or last entry in directory + if(directory->blockIndex != blockIndex) + BlockRead(directory, blockIndex); + directory->blockOffset = blockOffset; + } + else + { + // Backup to empty slot + if(directory->blockIndex != blockIndexEmpty) + BlockRead(directory, blockIndexEmpty); + directory->blockOffset = blockOffsetEmpty; + } + return rc; +} + + +static int FileFindRecursive(OS_FILE *directory, char *name, + OS_FileEntry_t *fileEntry, char *filename) +{ + int rc, length; + + rc = FileOpen(directory, NULL, NULL); //Open root directory + for(;;) + { + if(name[0] == '/') + ++name; + for(length = 0; length < FILE_NAME_SIZE; ++length) + { + if(name[length] == 0 || name[length] == '/') + break; + filename[length] = name[length]; + } + filename[length] = 0; + rc = FileFind(directory, filename, fileEntry); //Find file + if(rc) + { + // File not found + fileEntry->mediaType = directory->fileEntry.mediaType; + fileEntry->blockSize = directory->fileEntry.blockSize; + fileEntry->valid = 0; + if(strstr(name, "/") == NULL) + return rc; + else + return -2; //can't find parent directory + } + name += length; + if(name[0]) + rc = FileOpen(directory, filename, fileEntry); //Open subdir + else + break; + } + return rc; +} + + +OS_FILE *OS_fopen(char *name, char *mode) +{ + OS_FILE *file; + OS_FileEntry_t fileEntry; + OS_FILE dir; + char filename[FILE_NAME_SIZE]; //Name without directories + int rc; + + if(rootFileEntry.blockIndex == 0) + { + // Mount file system + mutexFilesys = OS_MutexCreate("filesys"); + memset(&dir, 0, sizeof(OS_FILE)); + dir.fileEntry.blockSize = BLOCK_SIZE; + //dir.fileEntry.mediaType = FILE_MEDIA_FLASH; //Test flash + BlockRead(&dir, BLOCK_MALLOC); + strcpy(rootFileEntry.name, "/"); + rootFileEntry.mediaType = dir.fileEntry.mediaType; + rootFileEntry.blockIndex = dir.blockIndex; + rootFileEntry.blockSize = dir.fileEntry.blockSize; + rootFileEntry.isDirectory = 1; + BlockRead(&dir, BLOCK_EOF); //Flush data +#ifdef INCLUDE_FLASH + file = OS_fopen("flash", "w+"); + if(file == NULL) + return NULL; + file->fileEntry.isDirectory = 1; + file->fileEntry.mediaType = FILE_MEDIA_FLASH; + file->fileEntry.blockSize = FLASH_BLOCK_SIZE; + file->blockLocal = file->block; + file->block = NULL; + rc = MediaBlockInit(); + if(rc == 1) + BlockRead(file, BLOCK_MALLOC); + else + BlockRead(file, FLASH_START); + file->fileEntry.blockIndex = file->blockIndex; + OS_fclose(file); +#endif + } + + file = (OS_FILE*)malloc(sizeof(OS_FILE)); + if(file == NULL) + return NULL; + OS_MutexPend(mutexFilesys); + if(name[0] == 0 || strcmp(name, "/") == 0) + { + FileOpen(file, NULL, NULL); + OS_MutexPost(mutexFilesys); + return file; + } + if(mode[0] == 'w') + { + //Don't over write a directory + fileEntry.isDirectory = 0; + rc = FileFindRecursive(&dir, name, &fileEntry, filename); + if(dir.blockLocal) + free(dir.blockLocal); + if(rc == 0) + { + if(fileEntry.isDirectory) + { + free(file); + return NULL; + } + OS_fdelete(name); + } + } + rc = FileFindRecursive(&dir, name, &fileEntry, filename); + if(dir.blockLocal) + free(dir.blockLocal); + if(rc == -2 || (rc && mode[0] == 'r')) + { + free(file); + OS_MutexPost(mutexFilesys); + return NULL; + } + if(rc) + fileEntry.valid = 0; + rc = FileOpen(file, filename, &fileEntry); //Open file + file->fullname[0] = 0; + strncat(file->fullname, name, FULL_NAME_SIZE); + OS_MutexPost(mutexFilesys); + if(mode[0] == 'a') + OS_fseek(file, 0, 2); //goto end of file + return file; +} + + +void OS_fclose(OS_FILE *file) +{ + OS_FileEntry_t fileEntry; + OS_FILE dir; + char filename[FILE_NAME_SIZE]; + int rc; + + if(file->fileModified) + { + // Write file->fileEntry into parent directory + OS_MutexPend(mutexFilesys); + BlockRead(file, BLOCK_EOF); + rc = FileFindRecursive(&dir, file->fullname, &fileEntry, filename); + if(file->fileEntry.mediaType == FILE_MEDIA_FLASH && rc == 0) + { + // Invalidate old entry and add new entry at the end + fileEntry.valid = 0; + OS_fwrite(&fileEntry, sizeof(OS_FileEntry_t), 1, &dir); + FileFind(&dir, "endoffile", &fileEntry); + } + OS_fwrite(&file->fileEntry, sizeof(OS_FileEntry_t), 1, &dir); + BlockRead(&dir, BLOCK_EOF); //flush data + if(dir.blockLocal) + free(dir.blockLocal); + OS_MutexPost(mutexFilesys); + } + if(file->blockLocal) + free(file->blockLocal); + free(file); +} + + +int OS_fmkdir(char *name) +{ + OS_FILE *file; + file = OS_fopen(name, "w+"); + if(file == NULL) + return -1; + file->fileEntry.isDirectory = 1; + OS_fclose(file); + return 0; +} + + +void OS_fdelete(char *name) +{ + OS_FILE dir, file; + OS_FileEntry_t fileEntry; + int rc; + uint32 blockIndex; + char filename[FILE_NAME_SIZE]; //Name without directories + + OS_MutexPend(mutexFilesys); + rc = FileFindRecursive(&dir, name, &fileEntry, filename); + if(rc == 0) + { + FileOpen(&file, NULL, &fileEntry); + for(blockIndex = file.blockIndex; file.block->next != BLOCK_EOF; blockIndex = file.blockIndex) + { + BlockRead(&file, file.block->next); + MediaBlockFree(&file, blockIndex); + } + MediaBlockFree(&file, blockIndex); + fileEntry.valid = 0; + OS_fwrite((char*)&fileEntry, sizeof(OS_FileEntry_t), 1, &dir); + BlockRead(&dir, BLOCK_EOF); + if(file.blockLocal) + free(file.blockLocal); + } + if(dir.blockLocal) + free(dir.blockLocal); + OS_MutexPost(mutexFilesys); +} + + +int OS_flength(char *entry) +{ + OS_FileEntry_t *entry2=(OS_FileEntry_t*)entry; + return entry2->length; +} + + +int OS_fdir(OS_FILE *dir, char name[64]) +{ + OS_FileEntry_t *fileEntry = (OS_FileEntry_t*)name; + int count; + for(;;) + { + count = OS_fread(fileEntry, sizeof(OS_FileEntry_t), 1, dir); + if(count == 0 || fileEntry->blockIndex == BLOCK_EOF) + return -1; + if(fileEntry->valid == 1) + break; + } + return 0; +} + +/*************************************************/ +#define TEST_FILES +#ifdef TEST_FILES +int DirRecursive(char *name) +{ + OS_FileEntry_t fileEntry; + OS_FILE *dir; + char fullname[FULL_NAME_SIZE]; + int rc; + + dir = OS_fopen(name, "r"); + for(;;) + { + rc = OS_fdir(dir, (char*)&fileEntry); + if(rc) + break; + printf("%s %d\n", fileEntry.name, fileEntry.length); + if(fileEntry.isDirectory) + { + if(strcmp(name, "/") == 0) + sprintf(fullname, "/%s", fileEntry.name); + else + sprintf(fullname, "%s/%s", name, fileEntry.name); + DirRecursive(fullname); + } + } + OS_fclose(dir); + return 0; +} + +int OS_ftest(void) +{ + OS_FILE *file; + char *buf; + int count; + int i, j; + + buf = (char*)malloc(5000); + memset(buf, 0, 5000); + for(count = 0; count < 4000; ++count) + buf[count] = (char)('A' + (count % 26)); + OS_fmkdir("dir"); + OS_fmkdir("/dir/subdir"); + file = OS_fopen("/dir/subdir/test.txt", "w"); + count = OS_fwrite(buf, 1, 4000, file); + OS_fclose(file); + memset(buf, 0, 5000); + file = OS_fopen("/dir/subdir/test.txt", "r"); + count = OS_fread(buf, 1, 5000, file); + OS_fclose(file); + printf("(%s)\n", buf); + + DirRecursive("/"); + + for(i = 0; i < 5; ++i) + { + sprintf(buf, "/dir%d", i); + OS_fmkdir(buf); + for(j = 0; j < 5; ++j) + { + sprintf(buf, "/dir%d/file%d%d", i, i, j); + file = OS_fopen(buf, "w"); + sprintf(buf, "i=%d j=%d", i, j); + OS_fwrite(buf, 1, 8, file); + OS_fclose(file); + } + } + + OS_fdelete("/dir1/file12"); + DirRecursive("/"); + file = OS_fopen("/baddir/myfile.txt", "w"); + if(file) + printf("ERROR!\n"); + + for(i = 0; i < 5; ++i) + { + for(j = 0; j < 5; ++j) + { + sprintf(buf, "/dir%d/file%d%d", i, i, j); + file = OS_fopen(buf, "r"); + if(file) + { + count = OS_fread(buf, 1, 500, file); + printf("i=%d j=%d count=%d (%s)\n", i, j, count, buf); + OS_fclose(file); + } + } + } + + OS_fdelete("/dir/subdir/test.txt"); + OS_fdelete("/dir/subdir"); + OS_fdelete("/dir"); + for(i = 0; i < 5; ++i) + { + for(j = 0; j < 5; ++j) + { + sprintf(buf, "/dir%d/file%d%d", i, i, j); + OS_fdelete(buf); + } + sprintf(buf, "/dir%d", i); + OS_fdelete(buf); + } + + DirRecursive("/"); + + free(buf); + return 0; +} +#endif //TEST_FILES diff --git a/kernel/flash.c b/kernel/flash.c new file mode 100644 index 0000000..57f0a83 --- /dev/null +++ b/kernel/flash.c @@ -0,0 +1,52 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Flash + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/17/05 + * FILENAME: plasma.h + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma flash controller + * Only the lower 16-bits of each 32-bit word are connected -- + * this changes the address mapping to the flash. + * ByteOffset and bytes must be a multiple of two. + *--------------------------------------------------------------------*/ +#include "plasma.h" +#include "rtos.h" + + +void FlashRead(uint16 *dst, uint32 byteOffset, int bytes) +{ + volatile uint32 *ptr=(uint32*)(FLASH_BASE + (byteOffset << 1)); + *ptr = 0xff; //read mode + while(bytes > 0) + { + *dst++ = (uint16)*ptr++; + bytes -= 2; + } +} + + +void FlashWrite(uint16 *src, uint32 byteOffset, int bytes) +{ + volatile uint32 *ptr=(uint32*)(FLASH_BASE + (byteOffset << 1)); + while(bytes > 0) + { + *ptr = 0x40; //write mode + *ptr++ = *src++; //write data + while((*ptr & 0x80) == 0) //check status + ; + bytes -= 2; + } +} + + +void FlashErase(uint32 byteOffset) +{ + volatile uint32 *ptr=(uint32*)(FLASH_BASE + (byteOffset << 1)); + *ptr = 0x20; //erase block + *ptr = 0xd0; //confirm + while((*ptr & 0x80) == 0) //check status + ; +} diff --git a/kernel/http.c b/kernel/http.c new file mode 100644 index 0000000..e1462fa --- /dev/null +++ b/kernel/http.c @@ -0,0 +1,230 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma TCP/IP HTTP Server + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 4/22/06 + * FILENAME: http.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma TCP/IP HTTP Server + *--------------------------------------------------------------------*/ +#ifdef WIN32 +#include +#include +#include +#include +#define _LIBC +#endif +#include "rtos.h" +#include "tcpip.h" +#ifdef WIN32 +#define UartPrintf printf +#define OS_MQueueCreate(A,B,C) 0 +#define OS_MQueueGet(A,B,C) 0 +#define OS_ThreadCreate(A,B,C,D,E) 0 +#endif + +static const char pageGif[]= +{ + "HTTP/1.0 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: binary/gif\r\n\r\n" +}; +static const char pageGif2[]= +{ + "HTTP/1.0 200 OK\r\n" + "Content-Type: binary/gif\r\n\r\n" +}; +static const char pageBinary[]= +{ + "HTTP/1.0 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: binary/binary\r\n\r\n" +}; +static const char pageBinary2[]= +{ + "HTTP/1.0 200 OK\r\n" + "Content-Type: binary/binary\r\n\r\n" +}; +static const char pageHtml[]={ + "HTTP/1.0 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: text/html\r\n\r\n" +}; +static const char pageHtml2[]={ + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n\r\n" +}; +static const char pageText[]={ + "HTTP/1.0 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: text/text\r\n\r\n" +}; +static const char pageEmpty[]= +{ + "HTTP/1.0 404 OK\r\n" + "Content-Length: 0\r\n" + "Content-Type: text/html\r\n\r\n" +}; + +static const PageEntry_t *HtmlPages; +static int HtmlFiles; + + +void HttpServer(IPSocket *socket) +{ + uint8 buf[600]; + char filename[80]; + int bytes, i, length, len, needFooter; + char *name=NULL, *page=NULL; + const char *header, *header2; + + if(socket == NULL) + return; + if(socket->funcPtr != HttpServer && socket->funcPtr) + { + socket->funcPtr(socket); + return; + } + bytes = IPRead(socket, buf, sizeof(buf)-1); + if(bytes) + { + buf[bytes] = 0; + if(strncmp((char*)buf, "GET /", 5) == 0) + { + for(i = 0; ; ++i) + { + length = HtmlPages[i].length; + if(length == -1) + break; + name = (char*)HtmlPages[i].name; + page = (char*)HtmlPages[i].page; + len = (int)strlen(name); + if(strncmp((char*)buf+4, name, len) == 0) + break; + } +#if defined(WIN32) || defined(INCLUDE_FILESYS) + if(length == HTML_LENGTH_LIST_END && HtmlFiles) + { + FILE *file; + char *ptr; + + name = (char*)buf + 5; + ptr = strstr(name, " "); + if(ptr) + *ptr = 0; + strcpy(filename, "/web/"); + strncat(filename, name, 60); + file = fopen(filename, "rb"); + if(file == NULL) + { + strcpy(filename, "/flash/web/"); + strncat(filename, name, 60); + file = fopen(filename, "rb"); + } + if(file) + { + if(strstr(name, ".htm")) + IPWrite(socket, (uint8*)pageHtml2, sizeof(pageHtml2)-1); + else if(strstr(name, ".gif")) + IPWrite(socket, (uint8*)pageGif2, sizeof(pageGif2)-1); + else + IPWrite(socket, (uint8*)pageBinary2, sizeof(pageBinary2)-1); + for(;;) + { + len = fread(buf, 1, sizeof(buf), file); + if(len == 0) + break; + IPWrite(socket, (uint8*)buf, len); + } + fclose(file); + IPWriteFlush(socket); + IPClose(socket); + return; + } + } +#endif + if(length != HTML_LENGTH_LIST_END) + { + if(length == HTML_LENGTH_CALLBACK) + { + IPFuncPtr funcPtr = (IPFuncPtr)(uint32)page; + funcPtr(socket, buf, bytes); + return; + } + if(length == 0) + length = (int)strlen(page); + needFooter = 0; + header2 = NULL; + if(strstr(name, ".html")) + header = pageHtml; + else if(strstr(name, ".htm") || strcmp(name, "/ ") == 0) + { + header = pageHtml; + header2 = HtmlPages[0].page; + needFooter = 1; + } + else if(strstr(HtmlPages[i].name, ".gif")) + header = pageGif; + else + header = pageBinary; + len = 0; + if(header2) + len += (int)strlen(header2) + (int)strlen(HtmlPages[1].page); + sprintf((char*)buf, header, length + len); + IPWrite(socket, buf, (int)strlen((char*)buf)); + if(header2) + IPWrite(socket, (uint8*)header2, (int)strlen(header2)); + IPWrite(socket, (uint8*)page, length); + if(needFooter) + IPWrite(socket, (uint8*)HtmlPages[1].page, (int)strlen(HtmlPages[1].page)); + } + else + { + IPWrite(socket, (uint8*)pageEmpty, (int)strlen(pageEmpty)); + } + IPClose(socket); + } + } +} + + +void HttpInit(const PageEntry_t *Pages, int UseFiles) +{ + HtmlPages = Pages; + HtmlFiles = UseFiles; + IPOpen(IP_MODE_TCP, 0, 80, HttpServer); + IPOpen(IP_MODE_TCP, 0, 8080, HttpServer); +} + + +#ifdef EXAMPLE_HTML +//Example test code +static void MyProg(IPSocket *socket, char *request, int bytes) +{ + char *text="HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" + "Hello World!"; + (void)request; (void)bytes; + IPWrite(socket, (uint8*)text, (int)strlen(text)); + IPClose(socket); +} +static const PageEntry_t pageEntry[]= +{ //name, length, htmlText + {"/Header", 0, "Plasma CPU\n"}, + {"/Footer", 0, ""}, + {"/ ", 0, "

Home Page

Welcome! Other" + " myprog"}, + {"/other.htm ", 0, "

Other

Other."}, + //{"/binary/plasma.gif ", 1945, PlasmaGif}, + {"/cgi/myprog", HTML_LENGTH_CALLBACK, (char*)MyProg}, + {"", HTML_LENGTH_LIST_END, NULL} +}; +void HtmlInit(int UseFiles) +{ + (void)UseFiles; + HttpInit(pageEntry, 1); +} +#endif + + diff --git a/kernel/libc.c b/kernel/libc.c new file mode 100644 index 0000000..23c0c98 --- /dev/null +++ b/kernel/libc.c @@ -0,0 +1,658 @@ +/*-------------------------------------------------------------------- + * TITLE: ANSI C Library + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/17/05 + * FILENAME: libc.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Subset of the ANSI C library + *--------------------------------------------------------------------*/ +#define NO_ELLIPSIS +#include "rtos.h" + + +char *strcpy(char *dst, const char *src) +{ + char *dstSave=dst; + int c; + do + { + c = *dst++ = *src++; + } while(c); + return dstSave; +} + + +char *strncpy(char *dst, const char *src, int count) +{ + int c=1; + char *dstSave=dst; + while(count-- > 0 && c) + c = *dst++ = *src++; + *dst = 0; + return dstSave; +} + + +char *strcat(char *dst, const char *src) +{ + int c; + char *dstSave=dst; + while(*dst) + ++dst; + do + { + c = *dst++ = *src++; + } while(c); + return dstSave; +} + + +char *strncat(char *dst, const char *src, int count) +{ + int c=1; + char *dstSave=dst; + while(*dst && --count > 0) + ++dst; + while(--count > 0 && c) + c = *dst++ = *src++; + *dst = 0; + return dstSave; +} + + +int strcmp(const char *string1, const char *string2) +{ + int diff, c; + for(;;) + { + diff = *string1++ - (c = *string2++); + if(diff) + return diff; + if(c == 0) + return 0; + } +} + + +int strncmp(const char *string1, const char *string2, int count) +{ + int diff, c; + while(count-- > 0) + { + diff = *string1++ - (c = *string2++); + if(diff) + return diff; + if(c == 0) + return 0; + } + return 0; +} + + +char *strstr(const char *string, const char *find) +{ + int i; + for(;;) + { + for(i = 0; string[i] == find[i] && find[i]; ++i) ; + if(find[i] == 0) + return (char*)string; + if(*string++ == 0) + return NULL; + } +} + + +int strlen(const char *string) +{ + const char *base=string; + while(*string++) ; + return string - base - 1; +} + + +void *memcpy(void *dst, const void *src, unsigned long bytes) +{ + if(((uint32)dst | (uint32)src | bytes) & 3) + { + uint8 *Dst = (uint8*)dst, *Src = (uint8*)src; + while((int)bytes-- > 0) + *Dst++ = *Src++; + } + else + { + uint32 *Dst32 = (uint32*)dst, *Src32 = (uint32*)src; + bytes >>= 2; + while((int)bytes-- > 0) + *Dst32++ = *Src32++; + } + return dst; +} + + +void *memmove(void *dst, const void *src, unsigned long bytes) +{ + uint8 *Dst = (uint8*)dst; + uint8 *Src = (uint8*)src; + if(Dst < Src) + { + while((int)bytes-- > 0) + *Dst++ = *Src++; + } + else + { + Dst += bytes; + Src += bytes; + while((int)bytes-- > 0) + *--Dst = *--Src; + } + return dst; +} + + +int memcmp(const void *cs, const void *ct, unsigned long bytes) +{ + uint8 *Dst = (uint8*)cs; + uint8 *Src = (uint8*)ct; + int diff; + while((int)bytes-- > 0) + { + diff = *Dst++ - *Src++; + if(diff) + return diff; + } + return 0; +} + + +void *memset(void *dst, int c, unsigned long bytes) +{ + uint8 *Dst = (uint8*)dst; + while((int)bytes-- > 0) + *Dst++ = (uint8)c; + return dst; +} + + +int abs(int n) +{ + return n>=0 ? n : -n; +} + + +static uint32 Rand1=0x1f2bcda3; +int rand(void) +{ + Rand1 = 1664525 * Rand1 + 1013904223; //from D.E. Knuth and H.W. Lewis + return Rand1; +} + + +void srand(unsigned int seed) +{ + Rand1 = seed; +} + + +long strtol(const char *s, char **end, int base) +{ + int i; + unsigned long ch, value=0, neg=0; + + if(s[0] == '-') + { + neg = 1; + ++s; + } + if(s[0] == '0' && s[1] == 'x') + { + base = 16; + s += 2; + } + for(i = 0; i <= 8; ++i) + { + ch = *s++; + if('0' <= ch && ch <= '9') + ch -= '0'; + else if('A' <= ch && ch <= 'Z') + ch = ch - 'A' + 10; + else if('a' <= ch && ch <= 'z') + ch = ch - 'a' + 10; + else + break; + value = value * base + ch; + } + if(end) + *end = (char*)s - 1; + if(neg) + value = -(int)value; + return value; +} + + +int atoi(const char *s) +{ + return strtol(s, NULL, 10); +} + + +char *itoa(int num, char *dst, int base) +{ + int digit, negate=0, place; + char c, text[20]; + + if(base == 10 && num < 0) + { + num = -num; + negate = 1; + } + text[16] = 0; + for(place = 15; place >= 0; --place) + { + digit = (unsigned int)num % (unsigned int)base; + if(num == 0 && place < 15 && base == 10 && negate) + { + c = '-'; + negate = 0; + } + else if(digit < 10) + c = (char)('0' + digit); + else + c = (char)('a' + digit - 10); + text[place] = c; + num = (unsigned int)num / (unsigned int)base; + if(num == 0 && negate == 0) + break; + } + strcpy(dst, text + place); + return dst; +} + + +int sprintf(char *s, const char *format, + int arg0, int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6, int arg7) +{ + int argv[8]; + int argc=0, width, length; + char f, text[20], fill; + + argv[0] = arg0; argv[1] = arg1; argv[2] = arg2; argv[3] = arg3; + argv[4] = arg4; argv[5] = arg5; argv[6] = arg6; argv[7] = arg7; + + for(;;) + { + f = *format++; + if(f == 0) + return argc; + else if(f == '%') + { + width = 0; + fill = ' '; + f = *format++; + while('0' <= f && f <= '9') + { + width = width * 10 + f - '0'; + f = *format++; + } + if(f == '.') + { + fill = '0'; + f = *format++; + } + if(f == 0) + return argc; + + if(f == 'd') + { + memset(s, fill, width); + itoa(argv[argc++], text, 10); + length = (int)strlen(text); + if(width < length) + width = length; + strcpy(s + width - length, text); + } + else if(f == 'x' || f == 'f') + { + memset(s, '0', width); + itoa(argv[argc++], text, 16); + length = (int)strlen(text); + if(width < length) + width = length; + strcpy(s + width - length, text); + } + else if(f == 'c') + { + *s++ = (char)argv[argc++]; + *s = 0; + } + else if(f == 's') + { + length = strlen((char*)argv[argc]); + if(width > length) + { + memset(s, ' ', width - length); + s += width - length; + } + strcpy(s, (char*)argv[argc++]); + } + s += strlen(s); + } + else + { + if(f == '\n') + *s++ = '\r'; + *s++ = f; + if(f == '\r' && *format == '\n') + *s++ = *format++; + } + *s = 0; + } +} + + +int sscanf(const char *s, const char *format, + int arg0, int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6, int arg7) +{ + int argv[8]; + int argc=0; + char f, *ptr; + + argv[0] = arg0; argv[1] = arg1; argv[2] = arg2; argv[3] = arg3; + argv[4] = arg4; argv[5] = arg5; argv[6] = arg6; argv[7] = arg7; + + for(;;) + { + if(*s == 0) + return argc; + f = *format++; + if(f == 0) + return argc; + else if(f == '%') + { + while(isspace(*s)) + ++s; + f = *format++; + if(f == 0) + return argc; + if(f == 'd') + *(int*)argv[argc++] = strtol(s, (char**)&s, 10); + else if(f == 'x') + *(int*)argv[argc++] = strtol(s, (char**)&s, 16); + else if(f == 'c') + *(char*)argv[argc++] = *s++; + else if(f == 's') + { + ptr = (char*)argv[argc++]; + while(!isspace(*s)) + *ptr++ = *s++; + *ptr = 0; + } + } + else + { + while(*s && *s != f) + ++s; + if(*s) + ++s; + } + } +} + + +#ifdef INCLUDE_DUMP +/*********************** dump ***********************/ +void dump(const unsigned char *data, int length) +{ + int i, index=0, value; + char string[80]; + memset(string, 0, sizeof(string)); + for(i = 0; i < length; ++i) + { + if((i & 15) == 0) + { + if(strlen(string)) + printf("%s\n", string); + printf("%4x ", i); + memset(string, 0, sizeof(string)); + index = 0; + } + value = data[i]; + printf("%2x ", value); + if(isprint(value)) + string[index] = (char)value; + else + string[index] = '.'; + ++index; + } + for(; index < 16; ++index) + printf(" "); + printf("%s\n", string); +} +#endif //INCLUDE_DUMP + + +#ifdef INCLUDE_QSORT +/*********************** qsort ***********************/ +static void QsortSwap(char *base, long left, long right, long size) +{ + int temp, i; + char *ptrLeft, *ptrRight; + ptrLeft = base + left * size; + ptrRight = base + right * size; + for(i = 0; i < size; ++i) + { + temp = ptrLeft[i]; + ptrLeft[i] = ptrRight[i]; + ptrRight[i] = (char)temp; + } +} + + +//Modified from K&R +static void qsort2(void *base, long left, long right, long size, + int (*cmp)(const void *,const void *)) +{ + int i, last; + char *base2=(char*)base, *pivot; + if(left >= right) + return; + QsortSwap(base2, left, (left + right)/2, size); + last = left; + pivot = &base2[left*size]; + for(i = left + 1; i <= right; ++i) + { + if(cmp(&base2[i*size], pivot) < 0) + QsortSwap(base2, ++last, i, size); + } + QsortSwap(base2, left, last, size); + qsort2(base, left, last-1, size, cmp); + qsort2(base, last+1, right, size, cmp); +} + + +void qsort(void *base, + long n, + long size, + int (*cmp)(const void *,const void *)) +{ + qsort2(base, 0, n-1, size, cmp); +} + + +void *bsearch(const void *key, + const void *base, + long n, + long size, + int (*cmp)(const void *,const void *)) +{ + long cond, low=0, high=n-1, mid; + char *base2=(char*)base; + while(low <= high) + { + mid = (low + high)/2; + cond = cmp(key, &base2[mid*size]); + if(cond < 0) + high = mid - 1; + else if(cond > 0) + low = mid + 1; + else + return &base2[mid * size]; + } + return NULL; +} +#endif //INCLUDE_QSORT + + +#ifdef INCLUDE_TIMELIB +/************************* time.h ***********************/ +#define SEC_PER_YEAR (365L*24*60*60) +#define SEC_PER_DAY (24L*60*60) +//typedef unsigned long time_t; //start at 1/1/80 +//struct tm { +// int tm_sec; //(0,59) +// int tm_min; //(0,59) +// int tm_hour; //(0,23) +// int tm_mday; //(1,31) +// int tm_mon; //(0,11) +// int tm_year; //(0,n) from 1900 +// int tm_wday; //(0,6) calculated +// int tm_yday; //(0,365) calculated +// int tm_isdst; //hour adjusted for day light savings +//}; +static const unsigned short DaysUntilMonth[]= + {0,31,59,90,120,151,181,212,243,273,304,334,365}; +static const unsigned short DaysInMonth[]= + {31,28,31,30,31,30,31,31,30,31,30,31}; +static time_t DstTimeIn, DstTimeOut; + + +/* Leap year if divisible by 4. Centenary years should only be + leap-years if they were divisible by 400. */ +static int IsLeapYear(int year) +{ + return(((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)); +} + +time_t mktime(struct tm *tp) +{ + time_t seconds; + unsigned long days, y, year; + + days = tp->tm_mday - 1 + DaysUntilMonth[tp->tm_mon] + + 365 * (tp->tm_year - 80); + seconds = (unsigned long)tp->tm_sec + 60L * (tp->tm_min + + 60L * (tp->tm_hour + 24L * days)); + if(tp->tm_isdst) + seconds -= 60 * 60; + year = 1900 + tp->tm_year - (tp->tm_mon < 2); + for(y = 1980; y <= year; y += 4) + { + if(y % 100 != 0 || y % 400 == 0) + seconds += SEC_PER_DAY; + } + return seconds; +} + + +void gmtime_r(const time_t *tp, struct tm *out) +{ + time_t seconds, delta, secondsIn=*tp; + int isLeapYear; + unsigned long year, month; + + out->tm_isdst = 0; + if(DstTimeIn <= secondsIn && secondsIn < DstTimeOut) + { + secondsIn += 60 * 60; + out->tm_isdst = 1; + } + seconds = secondsIn; + for(year = 0; ; ++year) + { + delta = SEC_PER_YEAR + IsLeapYear(1980 + year) * SEC_PER_DAY; + if(seconds >= delta) + seconds -= delta; + else + break; + } + out->tm_year = year + 80; + isLeapYear = IsLeapYear(1980 + year); + for(month = 0; ; ++month) + { + delta = SEC_PER_DAY * (DaysInMonth[month] + (isLeapYear && (month == 1))); + if(seconds >= delta) + seconds -= delta; + else + break; + } + out->tm_mon = month; + out->tm_mday = seconds / SEC_PER_DAY; + out->tm_yday = DaysUntilMonth[month] + out->tm_mday; + seconds -= out->tm_mday * SEC_PER_DAY; + ++out->tm_mday; + out->tm_hour = seconds / (60 * 60); + seconds -= out->tm_hour * (60 * 60); + out->tm_min = seconds / 60; + seconds -= out->tm_min * 60; + out->tm_sec = seconds; + seconds = secondsIn % (SEC_PER_DAY * 7); + out->tm_wday = (seconds / SEC_PER_DAY + 2) % 7; /* 1/1/80 is a Tue */ + //printf("%4.d/%2.d/%2.d:%2.d:%2.d:%2.d\n", + // out->tm_year+1900, out->tm_mon+1, out->tm_mday, + // out->tm_hour, out->tm_min, out->tm_sec); +} + + +void gmtimeDst(time_t dstTimeIn, time_t dstTimeOut) +{ + DstTimeIn = dstTimeIn; + DstTimeOut = dstTimeOut; +} + + +//DST from 2am on the second Sunday in March to 2am first Sunday in November +void gmtimeDstSet(time_t *tp, time_t *dstTimeIn, time_t *dstTimeOut) +{ + time_t seconds, timeIn, timeOut; + struct tm tmDate; + int year, days; + + DstTimeIn = 0; + DstTimeOut = 0; + gmtime_r(tp, &tmDate); + year = tmDate.tm_year; + + //March 1, year, 2AM -> second Sunday + tmDate.tm_year = year; + tmDate.tm_mon = 2; + tmDate.tm_mday = 1; + tmDate.tm_hour = 2; + tmDate.tm_min = 0; + tmDate.tm_sec = 0; + seconds = mktime(&tmDate); + gmtime_r(&seconds, &tmDate); + days = 7 - tmDate.tm_wday + 7; + *dstTimeIn = timeIn = seconds + days * SEC_PER_DAY; + + //November 1, year, 2AM -> first Sunday + tmDate.tm_year = year; + tmDate.tm_mon = 10; + tmDate.tm_mday = 1; + tmDate.tm_hour = 2; + tmDate.tm_min = 0; + tmDate.tm_sec = 0; + seconds = mktime(&tmDate); + gmtime_r(&seconds, &tmDate); + days = 7 - tmDate.tm_wday; + *dstTimeOut = timeOut = seconds + days * SEC_PER_DAY; + + DstTimeIn = timeIn; + DstTimeOut = timeOut; +} +#endif //INCLUDE_TIMELIB + diff --git a/kernel/makefile b/kernel/makefile new file mode 100644 index 0000000..7ac265e --- /dev/null +++ b/kernel/makefile @@ -0,0 +1,192 @@ +# Makefile for Plasma RTOS and Plasma TCP/IP stack + +ifeq ($(LANG),) + +# Customize for Windows +# The MIPS gcc compiler must use the cygwin1.dll that came with the compiler. +CC_X86 = cl /O1 /nologo /I..\tools +CP = copy +RM = del +DWIN32 = -DWIN32 +BIN_MIPS = ..\gccmips_elf +TOOLS_DIR = ..\tools\\ +TOOLS2_DIR = ..\tools +APP_DIR = ..\App\\ +LINUX_PWD = +ALIASING = +GCC_MIPS = $(BIN_MIPS)\gcc $(CFLAGS) +AS_MIPS = $(BIN_MIPS)\as +LD_MIPS = $(BIN_MIPS)\ld +DUMP_MIPS = $(BIN_MIPS)\objdump +CONVERT_BIN = $(TOOLS_DIR)convert_bin.exe +OBJ = obj +CFLAGS_X86 = /c /DWIN32 +LFLAGS_X86 = + +else + +# Customized for Linux +# See the GNU GCC tab on the Opencores Plasma page +CC_X86 = gcc -Wall -O -g -I../tools +CP = cp +RM = rm -rf +DWIN32 = +TOOLS_DIR = ../tools/ +TOOLS2_DIR = ../tools +APP_DIR = ../App/ +LINUX_PWD = ./ +ALIASING = -fno-strict-aliasing +GCC_MIPS = $(BIN_MIPS)mips-elf-gcc $(CFLAGS) +AS_MIPS = $(BIN_MIPS)mips-elf-as +LD_MIPS = $(BIN_MIPS)mips-elf-ld +DUMP_MIPS = $(BIN_MIPS)mips-elf-objdump +CONVERT_BIN = $(TOOLS_DIR)convert_bin.exe +#CONVERT_BIN = $(BIN_MIPS)mips-elf-objcopy -I elf32-big -O binary test.axf test.bin +OBJ = o +CFLAGS_X86 = -c -DWIN32 -DLINUX +LFLAGS_X86 = -lm + +endif + +# Use software multiplier (don't use mult.vhd) +CFLAGS_SW_MULT = -mno-mul -DUSE_SW_MULT + +# Use 16 fewer registers (make reg_bank.vhd smaller) +CFLAGS_FEW_REGS = -ffixed-t0 -ffixed-t1 -ffixed-t2 -ffixed-t3 -ffixed-t4 -ffixed-t5 -ffixed-t6 -ffixed-t7 -ffixed-s0 -ffixed-s1 -ffixed-s2 -ffixed-s3 -ffixed-s4 -ffixed-s5 -ffixed-s6 -ffixed-s7 + +CFLAGS = -O2 -Wall -c -s -I$(TOOLS2_DIR) -msoft-float -fno-builtin +#CFLAGS += $(CFLAGS_SW_MULT) +#CFLAGS += $(CFLAGS_FEW_REGS) + +# Build just the Plasma RTOS for Plasma CPU +rtos: + $(AS_MIPS) -o boot.o $(TOOLS_DIR)boot.asm + $(GCC_MIPS) rtos.c + $(GCC_MIPS) libc.c + $(GCC_MIPS) uart.c + $(GCC_MIPS) rtos_test.c + $(GCC_MIPS) math.c $(ALIASING) + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf \ + boot.o rtos.o libc.o uart.o rtos_test.o math.o + $(CONVERT_BIN) + @sort test2.map + @$(DUMP_MIPS) --disassemble test.axf > test.lst + +# Build the Plasma RTOS, Plasma TCP/IP stack, and web server for the Plasma CPU +# Use the serial port and etermip for TCP/IP packets +rtos_tcpip: + $(AS_MIPS) -o boot.o $(TOOLS_DIR)boot.asm + $(GCC_MIPS) rtos.c + $(GCC_MIPS) libc.c + $(GCC_MIPS) uart.c + $(GCC_MIPS) rtos_test.c -DINCLUDE_HTML -DINCLUDE_CONSOLE + $(GCC_MIPS) math.c $(ALIASING) + $(GCC_MIPS) tcpip.c -DINCLUDE_FILESYS + $(GCC_MIPS) http.c -DINCLUDE_FILESYS -DEXAMPLE_HTML + $(GCC_MIPS) netutil.c + $(GCC_MIPS) filesys.c + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf \ + boot.o rtos.o libc.o uart.o rtos_test.o math.o tcpip.o \ + http.o netutil.o filesys.o + $(CONVERT_BIN) + @sort test2.map + @$(DUMP_MIPS) --disassemble test.axf > test.lst + +# Use Ethernet for TCP/IP packets, use flash file system +rtos_tcpip_eth: + $(AS_MIPS) -o boot.o $(TOOLS_DIR)boot.asm + $(GCC_MIPS) rtos.c + $(GCC_MIPS) libc.c + $(GCC_MIPS) uart.c -DNO_PACKETS + $(GCC_MIPS) rtos_test.c -DINCLUDE_ETH -DINCLUDE_CONSOLE + $(GCC_MIPS) math.c $(ALIASING) + $(GCC_MIPS) tcpip.c -DINCLUDE_FILESYS + $(GCC_MIPS) http.c -DINCLUDE_FILESYS -DEXAMPLE_HTML + $(GCC_MIPS) netutil.c -DINCLUDE_FLASH -DDLL_SETUP + $(GCC_MIPS) filesys.c -DINCLUDE_FLASH + $(GCC_MIPS) ethernet.c + $(GCC_MIPS) flash.c + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf \ + boot.o rtos.o libc.o uart.o rtos_test.o math.o tcpip.o \ + http.o netutil.o filesys.o ethernet.o flash.o + $(CONVERT_BIN) + @sort test2.map + @$(DUMP_MIPS) --disassemble test.axf > test.lst + +# Build full test application. (Use rtos_tcpip_eth instead.) +rtosfull: + $(AS_MIPS) -o boot.o $(TOOLS_DIR)boot.asm + $(GCC_MIPS) rtos.c + $(GCC_MIPS) libc.c + $(GCC_MIPS) uart.c -DNO_PACKETS + $(GCC_MIPS) rtos_test.c -DINCLUDE_ETH -DINCLUDE_CONSOLE + $(GCC_MIPS) math.c $(ALIASING) + $(GCC_MIPS) tcpip.c -DINCLUDE_FILESYS + $(GCC_MIPS) http.c -DINCLUDE_FILESYS + $(GCC_MIPS) netutil.c -DINCLUDE_FLASH -DDLL_SETUP + $(GCC_MIPS) filesys.c -DINCLUDE_FLASH + $(GCC_MIPS) ethernet.c + $(GCC_MIPS) flash.c + $(GCC_MIPS) -I. $(APP_DIR)html.c -DMainThread=HtmlThread + $(GCC_MIPS) -I. $(APP_DIR)image.c + $(GCC_MIPS) -I. $(APP_DIR)tictac.c + $(GCC_MIPS) -I. $(APP_DIR)tic3d.c + $(GCC_MIPS) -I. $(APP_DIR)connect4.c + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf \ + boot.o rtos.o libc.o uart.o rtos_test.o math.o tcpip.o \ + http.o netutil.o filesys.o ethernet.o flash.o \ + html.o image.o tictac.o tic3d.o connect4.o + $(CONVERT_BIN) + @sort test2.map + @$(DUMP_MIPS) --disassemble test.axf > test.lst + +# Create a separate Dynamically Linked Library executable +# ftp test.bin to /flash/web/dlltest +# telnet to board and execute "dlltest" +dlltest: + $(GCC_MIPS) -G0 dlltest.c + $(LD_MIPS) -Ttext 0x10100000 -s -N -o test.axf dlltest.o + $(CONVERT_BIN) + @$(DUMP_MIPS) --disassemble test.axf > test.lst + +# Test the RTOS running on a PC +testrtos: + @$(CC_X86) $(CFLAGS_X86) rtos.c + @$(CC_X86) $(CFLAGS_X86) libc.c + @$(CC_X86) $(CFLAGS_X86) uart.c + @$(CC_X86) $(CFLAGS_X86) rtos_test.c + @$(CC_X86) $(CFLAGS_X86) math.c $(ALIASING) + @$(CC_X86) $(LFLAGS_X86) -o testrtos.exe rtos.$(OBJ) libc.$(OBJ) uart.$(OBJ) rtos_test.$(OBJ) math.$(OBJ) + $(LINUX_PWD)testrtos.exe + +# Test the TCP/IP protocol stack running on a PC (requires Windows) +testip: + @$(CC_X86) $(CFLAGS_X86) tcpip.c + @$(CC_X86) $(CFLAGS_X86) http.c /DEXAMPLE_HTML + @$(CC_X86) $(CFLAGS_X86) netutil.c + @$(CC_X86) $(CFLAGS_X86) filesys.c + @$(CC_X86) $(CFLAGS_X86) libc.c /I$(TOOLS_DIR) + @$(CC_X86) $(CFLAGS_X86) /DSIMULATE_PLASMA $(TOOLS_DIR)etermip.c + @$(CC_X86) $(CFLAGS_X86) os_stubs.c + @$(CC_X86) -o testip.exe etermip.obj $(TOOLS_DIR)wpcap.lib \ + tcpip.obj http.obj netutil.obj filesys.obj libc.obj os_stubs.obj + @echo Try http://plasmb/. Try telnet plasmb. Try ftp plasmb. + $(LINUX_PWD)testip.exe + +clean: + -$(RM) *.o *.obj *.axf *.map *.lst *.hex *.txt *.bin *.exe + +# Run a Plasma CPU opcode simulator (can execute rtos target) +run: + @$(TOOLS_DIR)mlite.exe test.bin + +disassemble: + -@$(TOOLS_DIR)mlite.exe test.bin BD > test.txt + +# Start the EtermIP terminal program to download the code to the Plasma CPU +# and permit an Ethernet packets to be transfered. +download: + @echo Reset board before downloading code + $(TOOLS_DIR)etermip.exe + + diff --git a/kernel/math.c b/kernel/math.c new file mode 100644 index 0000000..976f5d4 --- /dev/null +++ b/kernel/math.c @@ -0,0 +1,692 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Floating Point Library + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 3/2/06 + * FILENAME: math.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma Floating Point Library + *-------------------------------------------------------------------- + * IEEE_fp = sign(1) | exponent(8) | fraction(23) + * cos(x)=1-x^2/2!+x^4/4!-x^6/6!+... + * exp(x)=1+x+x^2/2!+x^3/3!+... + * ln(1+x)=x-x^2/2+x^3/3-x^4/4+... + * atan(x)=x-x^3/3+x^5/5-x^7/7+... + * pow(x,y)=exp(y*ln(x)) + * x=tan(a+b)=(tan(a)+tan(b))/(1-tan(a)*tan(b)) + * atan(x)=b+atan((x-atan(b))/(1+x*atan(b))) + * ln(a*x)=ln(a)+ln(x); ln(x^n)=n*ln(x) + *--------------------------------------------------------------------*/ +#include "rtos.h" + +//#define USE_SW_MULT +#if !defined(WIN32) && !defined(USE_SW_MULT) +#define USE_MULT64 +#endif + +#define PI ((float)3.1415926) +#define PI_2 ((float)(PI/2.0)) +#define PI2 ((float)(PI*2.0)) + +#define FtoL(X) (*(unsigned long*)&(X)) +#define LtoF(X) (*(float*)&(X)) + + +float FP_Neg(float a_fp) +{ + unsigned long a; + a = FtoL(a_fp); + a ^= 0x80000000; + return LtoF(a); +} + + +float FP_Add(float a_fp, float b_fp) +{ + unsigned long a, b, c; + unsigned long as, bs, cs; //sign + long ae, af, be, bf, ce, cf; //exponent and fraction + a = FtoL(a_fp); + b = FtoL(b_fp); + as = a >> 31; //sign + ae = (a >> 23) & 0xff; //exponent + af = 0x00800000 | (a & 0x007fffff); //fraction + bs = b >> 31; + be = (b >> 23) & 0xff; + bf = 0x00800000 | (b & 0x007fffff); + if(ae > be) + { + if(ae - be < 30) + bf >>= ae - be; + else + bf = 0; + ce = ae; + } + else + { + if(be - ae < 30) + af >>= be - ae; + else + af = 0; + ce = be; + } + cf = (as ? -af : af) + (bs ? -bf : bf); + cs = cf < 0; + cf = cf>=0 ? cf : -cf; + if(cf == 0) + return LtoF(cf); + while(cf & 0xff000000) + { + ++ce; + cf >>= 1; + } + while((cf & 0xff800000) == 0) + { + --ce; + cf <<= 1; + } + c = (cs << 31) | (ce << 23) | (cf & 0x007fffff); + if(ce < 1) + c = 0; + return LtoF(c); +} + + +float FP_Sub(float a_fp, float b_fp) +{ + return FP_Add(a_fp, FP_Neg(b_fp)); +} + + +float FP_Mult(float a_fp, float b_fp) +{ + unsigned long a, b, c; + unsigned long as, af, bs, bf, cs, cf; + long ae, be, ce; +#ifndef USE_MULT64 + unsigned long a2, a1, b2, b1, med1, med2; +#endif + unsigned long hi, lo; + a = FtoL(a_fp); + b = FtoL(b_fp); + as = a >> 31; + ae = (a >> 23) & 0xff; + af = 0x00800000 | (a & 0x007fffff); + bs = b >> 31; + be = (b >> 23) & 0xff; + bf = 0x00800000 | (b & 0x007fffff); + cs = as ^ bs; +#ifndef USE_MULT64 + a1 = af & 0xffff; + a2 = af >> 16; + b1 = bf & 0xffff; + b2 = bf >> 16; + lo = a1 * b1; + med1 = a2 * b1 + (lo >> 16); + med2 = a1 * b2; + hi = a2 * b2 + (med1 >> 16) + (med2 >> 16); + med1 = (med1 & 0xffff) + (med2 & 0xffff); + hi += (med1 >> 16); + lo = (med1 << 16) | (lo & 0xffff); +#else + lo = OS_AsmMult(af, bf, &hi); +#endif + cf = (hi << 9) | (lo >> 23); + ce = ae + be - 0x80 + 1; + if(cf == 0) + return LtoF(cf); + while(cf & 0xff000000) + { + ++ce; + cf >>= 1; + } + c = (cs << 31) | (ce << 23) | (cf & 0x007fffff); + if(ce < 1) + c = 0; + return LtoF(c); +} + + +float FP_Div(float a_fp, float b_fp) +{ + unsigned long a, b, c; + unsigned long as, af, bs, bf, cs, cf; + unsigned long a1, b1; +#ifndef USE_MULT64 + unsigned long a2, b2, med1, med2; +#endif + unsigned long hi, lo; + long ae, be, ce, d; + a = FtoL(a_fp); + b = FtoL(b_fp); + as = a >> 31; + ae = (a >> 23) & 0xff; + af = 0x00800000 | (a & 0x007fffff); + bs = b >> 31; + be = (b >> 23) & 0xff; + bf = 0x00800000 | (b & 0x007fffff); + cs = as ^ bs; + ce = ae - (be - 0x80) + 6 - 8; + a1 = af << 4; //8 + b1 = bf >> 8; + cf = a1 / b1; + cf <<= 12; //8 +#if 1 /*non-quick*/ +#ifndef USE_MULT64 + a1 = cf & 0xffff; + a2 = cf >> 16; + b1 = bf & 0xffff; + b2 = bf >> 16; + lo = a1 * b1; + med1 =a2 * b1 + (lo >> 16); + med2 = a1 * b2; + hi = a2 * b2 + (med1 >> 16) + (med2 >> 16); + med1 = (med1 & 0xffff) + (med2 & 0xffff); + hi += (med1 >> 16); + lo = (med1 << 16) | (lo & 0xffff); +#else + lo = OS_AsmMult(cf, bf, &hi); +#endif + lo = (hi << 8) | (lo >> 24); + d = af - lo; //remainder + assert(-0xffff < d && d < 0xffff); + d <<= 16; + b1 = bf >> 8; + d = d / (long)b1; + cf += d; +#endif + if(cf == 0) + return LtoF(cf); + while(cf & 0xff000000) + { + ++ce; + cf >>= 1; + } + if(ce < 0) + ce = 0; + c = (cs << 31) | (ce << 23) | (cf & 0x007fffff); + if(ce < 1) + c = 0; + return LtoF(c); +} + + +long FP_ToLong(float a_fp) +{ + unsigned long a; + unsigned long as; + long ae; + long af, shift; + a = FtoL(a_fp); + as = a >> 31; + ae = (a >> 23) & 0xff; + af = 0x00800000 | (a & 0x007fffff); + af <<= 7; + shift = -(ae - 0x80 - 29); + if(shift > 0) + { + if(shift < 31) + af >>= shift; + else + af = 0; + } + af = as ? -af: af; + return af; +} + + +float FP_ToFloat(long af) +{ + unsigned long a; + unsigned long as, ae; + as = af>=0 ? 0: 1; + af = af>=0 ? af: -af; + ae = 0x80 + 22; + if(af == 0) + return LtoF(af); + while(af & 0xff000000) + { + ++ae; + af >>= 1; + } + while((af & 0xff800000) == 0) + { + --ae; + af <<= 1; + } + a = (as << 31) | (ae << 23) | (af & 0x007fffff); + return LtoF(a); +} + + +//0 iff a==b; 1 iff a>b; -1 iff a> 31; + bs = b >> 31; + if(as > bs) + return -1; + if(as < bs) + return 1; + gt = as ? -1 : 1; + ae = (a >> 23) & 0xff; + be = (b >> 23) & 0xff; + if(ae > be) + return gt; + if(ae < be) + return -gt; + af = 0x00800000 | (a & 0x007fffff); + bf = 0x00800000 | (b & 0x007fffff); + if(af > bf) + return gt; + return -gt; +} + + +int __ltsf2(float a, float b) +{ + return FP_Cmp(a, b); +} + +int __lesf2(float a, float b) +{ + return FP_Cmp(a, b); +} + +int __gtsf2(float a, float b) +{ + return FP_Cmp(a, b); +} + +int __gesf2(float a, float b) +{ + return FP_Cmp(a, b); +} + +int __eqsf2(float a, float b) +{ + return FtoL(a) != FtoL(b); +} + +int __nesf2(float a, float b) +{ + return FtoL(a) != FtoL(b); +} + + +float FP_Sqrt(float a) +{ + float x1, y1, x2, y2, x3; + long i; + x1 = FP_ToFloat(1); + y1 = FP_Sub(FP_Mult(x1, x1), a); //y1=x1*x1-a; + x2 = FP_ToFloat(100); + y2 = FP_Sub(FP_Mult(x2, x2), a); + for(i = 0; i < 10; ++i) + { + if(FtoL(y1) == FtoL(y2)) + return x2; + //x3=x2-(x1-x2)*y2/(y1-y2); + x3 = FP_Sub(x2, FP_Div(FP_Mult(FP_Sub(x1, x2), y2), FP_Sub(y1, y2))); + x1 = x2; + y1 = y2; + x2 = x3; + y2 = FP_Sub(FP_Mult(x2, x2), a); + } + return x2; +} + + +float FP_Cos(float rad) +{ + int n; + float answer, x2, top, bottom, sign; + while(FP_Cmp(rad, PI2) > 0) + rad = FP_Sub(rad, PI2); + while(FP_Cmp(rad, (float)0.0) < 0) + rad = FP_Add(rad, PI2); + answer = 1.0; + sign = 1.0; + if(FP_Cmp(rad, PI) >= 0) + { + rad = FP_Sub(rad, PI); + sign = FP_ToFloat(-1); + } + if(FP_Cmp(rad, PI_2) >= 0) + { + rad = FP_Sub(PI, rad); + sign = FP_Neg(sign); + } + x2 = FP_Mult(rad, rad); + top = 1.0; + bottom = 1.0; + for(n = 2; n < 12; n += 2) + { + top = FP_Mult(top, FP_Neg(x2)); + bottom = FP_Mult(bottom, FP_ToFloat((n - 1) * n)); + answer = FP_Add(answer, FP_Div(top, bottom)); + } + return FP_Mult(answer, sign); +} + + +float FP_Sin(float rad) +{ + const float pi_2=(float)(PI/2.0); + return FP_Cos(FP_Sub(rad, pi_2)); +} + + +float FP_Atan(float x) +{ + const float b=(float)(PI/8.0); + const float atan_b=(float)0.37419668; //atan(b); + int n; + float answer, x2, top; + if(FP_Cmp(x, (float)0.0) >= 0) + { + if(FP_Cmp(x, (float)1.0) > 0) + return FP_Sub(PI_2, FP_Atan(FP_Div((float)1.0, x))); + } + else + { + if(FP_Cmp(x, (float)-1.0) > 0) + return FP_Sub(-PI_2, FP_Atan(FP_Div((float)1.0, x))); + } + if(FP_Cmp(x, (float)0.45) > 0) + { + //answer = (x - atan_b) / (1 + x * atan_b); + answer = FP_Div(FP_Sub(x, atan_b), FP_Add(1.0, FP_Mult(x, atan_b))); + //answer = b + FP_Atan(answer) - (float)0.034633; /*FIXME fudge?*/ + answer = FP_Sub(FP_Add(b, FP_Atan(answer)), (float)0.034633); + return answer; + } + if(FP_Cmp(x, (float)-0.45) < 0) + { + x = FP_Neg(x); + //answer = (x - atan_b) / (1 + x * atan_b); + answer = FP_Div(FP_Sub(x, atan_b), FP_Add(1.0, FP_Mult(x, atan_b))); + //answer = b + FP_Atan(answer) - (float)0.034633; /*FIXME*/ + answer = FP_Sub(FP_Add(b, FP_Atan(answer)), (float)0.034633); + return FP_Neg(answer); + } + answer = x; + x2 = FP_Mult(FP_Neg(x), x); + top = x; + for(n = 3; n < 14; n += 2) + { + top = FP_Mult(top, x2); + answer = FP_Add(answer, FP_Div(top, FP_ToFloat(n))); + } + return answer; +} + + +float FP_Atan2(float y, float x) +{ + float answer,r; + r = y / x; + answer = FP_Atan(r); + if(FP_Cmp(x, (float)0.0) < 0) + { + if(FP_Cmp(y, (float)0.0) > 0) + answer = FP_Add(answer, PI); + else + answer = FP_Sub(answer, PI); + } + return answer; +} + + +float FP_Exp(float x) +{ + const float e2=(float)7.389056099; + const float inv_e2=(float)0.135335283; + float answer, top, bottom, mult; + int n; + + mult = 1.0; + while(FP_Cmp(x, (float)2.0) > 0) + { + mult = FP_Mult(mult, e2); + x = FP_Add(x, (float)-2.0); + } + while(FP_Cmp(x, (float)-2.0) < 0) + { + mult = FP_Mult(mult, inv_e2); + x = FP_Add(x, (float)2.0); + } + answer = FP_Add((float)1.0, x); + top = x; + bottom = 1.0; + for(n = 2; n < 15; ++n) + { + top = FP_Mult(top, x); + bottom = FP_Mult(bottom, FP_ToFloat(n)); + answer = FP_Add(answer, FP_Div(top, bottom)); + } + return FP_Mult(answer, mult); +} + + +float FP_Log(float x) +{ + const float log_2=(float)0.69314718; /*log(2.0)*/ + int n; + float answer, top, add; + add = 0.0; + while(FP_Cmp(x, 16.0) > 0) + { + x = FP_Mult(x, (float)0.0625); + add = FP_Add(add, (float)(log_2 * 4)); + } + while(FP_Cmp(x, 1.5) > 0) + { + x = FP_Mult(x, 0.5); + add = FP_Add(add, log_2); + } + while(FP_Cmp(x, 0.5) < 0) + { + x = FP_Mult(x, 2.0); + add = FP_Sub(add, log_2); + } + x = FP_Sub(x, 1.0); + answer = 0.0; + top = -1.0; + for(n = 1; n < 14; ++n) + { + top = FP_Mult(top, FP_Neg(x)); + answer = FP_Add(answer, FP_Div(top, FP_ToFloat(n))); + } + return FP_Add(answer, add); +} + + +float FP_Pow(float x, float y) +{ + return FP_Exp(y * FP_Log(x)); +} + + +/********************************************/ +//These five functions will only be used if the flag "-mno-mul" is enabled +#ifdef USE_SW_MULT +unsigned long __mulsi3(unsigned long a, unsigned long b) +{ + unsigned long answer = 0; + while(b) + { + if(b & 1) + answer += a; + a <<= 1; + b >>= 1; + } + return answer; +} + + +static unsigned long DivideMod(unsigned long a, unsigned long b, int doMod) +{ + unsigned long upper=a, lower=0; + int i; + a = b << 31; + for(i = 0; i < 32; ++i) + { + lower = lower << 1; + if(upper >= a && a && b < 2) + { + upper = upper - a; + lower |= 1; + } + a = ((b&2) << 30) | (a >> 1); + b = b >> 1; + } + if(!doMod) + return lower; + return upper; +} + + +unsigned long __udivsi3(unsigned long a, unsigned long b) +{ + return DivideMod(a, b, 0); +} + + +long __divsi3(long a, long b) +{ + long answer, negate=0; + if(a < 0) + { + a = -a; + negate = !negate; + } + if(b < 0) + { + b = -b; + negate = !negate; + } + answer = DivideMod(a, b, 0); + if(negate) + answer = -answer; + return answer; +} + + +unsigned long __umodsi3(unsigned long a, unsigned long b) +{ + return DivideMod(a, b, 1); +} +#endif + + +/*************** Test *****************/ +#ifdef WIN32 +#undef _LIBC +#include +#undef printf +#undef getch +int printf(const char *, ...); +struct { + char *name; + float low, high; + double (*func1)(double); + float (*func2)(float); +} test_info[]={ + {"cos", -2*PI, 2*PI, cos, FP_Cos}, + {"sin", -2*PI, 2*PI, sin, FP_Sin}, + {"atan", -3.0, 2.0, atan, FP_Atan}, + {"log", (float)0.01, (float)4.0, log, FP_Log}, + {"exp", (float)-5.01, (float)30.0, exp, FP_Exp}, + {"sqrt", (float)0.01, (float)1000.0, sqrt, FP_Sqrt} +}; + + +void TestMathFull(void) +{ + float a, b, c, d; + float error1, error2, error3, error4, error5; + int test; + + a = PI * PI; + b = PI; + c = FP_Div(a, b); + printf("%10f %10f %10f %10f %10f\n", + (double)a, (double)b, (double)(a/b), (double)c, (double)(a/b-c)); + a = a * 200; + for(b = -(float)2.718281828*100; b < 300; b += (float)23.678) + { + c = FP_Div(a, b); + d = a / b - c; + printf("%10f %10f %10f %10f %10f\n", + (double)a, (double)b, (double)(a/b), (double)c, (double)(a/b-c)); + } + //getch(); + + for(test = 0; test < 6; ++test) + { + printf("\nTesting %s\n", test_info[test].name); + for(a = test_info[test].low; + a <= test_info[test].high; + a += (test_info[test].high-test_info[test].low)/(float)20.0) + { + b = (float)test_info[test].func1(a); + c = test_info[test].func2(a); + d = b - c; + printf("%s %10f %10f %10f %10f\n", test_info[test].name, a, b, c, d); + } + //getch(); + } + + a = FP_ToFloat((long)6.0); + b = FP_ToFloat((long)2.0); + printf("%f %f\n", (double)a, (double)b); + c = FP_Add(a, b); + printf("add %f %f\n", (double)(a + b), (double)c); + c = FP_Sub(a, b); + printf("sub %f %f\n", (double)(a - b), (double)c); + c = FP_Mult(a, b); + printf("mult %f %f\n", (double)(a * b), (double)c); + c = FP_Div(a, b); + printf("div %f %f\n", (double)(a / b), (double)c); + //getch(); + + for(a = (float)-13756.54; a < (float)17400.0; a += (float)64.45) + { + for(b = (float)-875.36; b < (float)935.8; b += (float)36.7) + { + error1 = (float)1.0 - (a + b) / FP_Add(a, b); + error2 = (float)1.0 - (a * b) / FP_Mult(a, b); + error3 = (float)1.0 - (a / b) / FP_Div(a, b); + error4 = (float)1.0 - a / FP_ToFloat(FP_ToLong(a)); + error5 = error1 + error2 + error3 + error4; + if(error5 < 0.00005) + continue; + printf("ERROR!\n"); + printf("a=%f b=%f\n", (double)a, (double)b); + printf(" a+b=%f %f\n", (double)(a+b), (double)FP_Add(a, b)); + printf(" a*b=%f %f\n", (double)(a*b), (double)FP_Mult(a, b)); + printf(" a/b=%f %f\n", (double)(a/b), (double)FP_Div(a, b)); + printf(" a=%f %ld %f\n", (double)a, FP_ToLong(a), + (double)FP_ToFloat((long)a)); + printf(" %f %f %f %f\n", (double)error1, (double)error2, + (double)error3, (double)error4); + //if(error5 > 0.001) + // getch(); + } + } + printf("done.\n"); + //getch(); +} +#endif + + diff --git a/kernel/netutil.c b/kernel/netutil.c new file mode 100644 index 0000000..88095dc --- /dev/null +++ b/kernel/netutil.c @@ -0,0 +1,1159 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma TCP/IP Network Utilities + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 4/20/07 + * FILENAME: netutil.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma FTP server and FTP client and TFTP server and client + * and Telnet server. + *--------------------------------------------------------------------*/ +#undef INCLUDE_FILESYS +#define INCLUDE_FILESYS +#ifdef WIN32 +#include +#include +#include +#include +#define _LIBC +#endif +#include "rtos.h" +#include "tcpip.h" + +#ifdef DLL_SETUP +static void ConsoleRun(IPSocket *socket, char *argv[]); +#endif + +//******************* FTP Server ************************ +typedef struct { + IPSocket *socket; + int ip, port, bytes, done, canReceive; + FILE *file; +} FtpdInfo; + +static void FtpdSender(IPSocket *socket) +{ + unsigned char buf[600]; + int i, bytes, bytes2; + FtpdInfo *info = (FtpdInfo*)socket->userPtr; + + if(info == NULL || info->done) + return; + fseek(info->file, info->bytes, 0); + for(i = 0; i < 100000; ++i) + { + bytes = fread(buf, 1, 512, info->file); + bytes2 = IPWrite(socket, buf, bytes); + info->bytes += bytes2; + if(bytes != bytes2) + return; + if(bytes < 512) + { + fclose(info->file); + IPClose(socket); + info->done = 1; + IPPrintf(info->socket, "226 Done\r\n"); + return; + } + } +} + + +static void FtpdReceiver(IPSocket *socket) +{ + unsigned char buf[600]; + int bytes, state = socket->state; + FtpdInfo *info = (FtpdInfo*)socket->userPtr; + + if(info == NULL || info->done) + return; + do + { + bytes = IPRead(socket, buf, sizeof(buf)); + fwrite(buf, 1, bytes, info->file); + } while(bytes); + + if(state > IP_TCP) + { + fclose(info->file); + info->done = 1; + IPPrintf(info->socket, "226 Done\r\n"); + IPClose(socket); + return; + } +} + + +static void FtpdServer(IPSocket *socket) +{ + uint8 buf[600]; + int bytes; + int ip0, ip1, ip2, ip3, port0, port1; + IPSocket *socketOut; + FtpdInfo *info = (FtpdInfo*)socket->userPtr; + + if(socket == NULL) + return; + bytes = IPRead(socket, buf, sizeof(buf)-1); + buf[bytes] = 0; + //printf("(%s)\n", buf); + if(socket->userPtr == NULL) + { + info = (FtpdInfo*)malloc(sizeof(FtpdInfo)); + if(info == NULL) + return; + memset(info, 0, sizeof(FtpdInfo)); + socket->userPtr = info; + info->socket = socket; + socket->timeoutReset = 60; + IPPrintf(socket, "220 Connected to Plasma\r\n"); + } + else if(socket->userPtr == (void*)-1) + { + return; + } + else if(strstr((char*)buf, "USER")) + { + if(strstr((char*)buf, "PlasmaSend")) + info->canReceive = 1; + IPPrintf(socket, "331 Password?\r\n"); + } + else if(strstr((char*)buf, "PASS")) + { + IPPrintf(socket, "230 Logged in\r\n"); + } + else if(strstr((char*)buf, "PORT")) + { + sscanf((char*)buf + 5, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1); + info->ip = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; + info->port = (port0 << 8) | port1; + //printf("ip=0x%x port=%d\n", info->ip, info->port); + IPPrintf(socket, "200 OK\r\n"); + } + else if(strstr((char*)buf, "RETR") || strstr((char*)buf, "STOR")) + { + char *ptr = strstr((char*)buf, "\r"); + if(ptr) + *ptr = 0; + info->file = NULL; + info->bytes = 0; + info->done = 0; + if(strstr((char*)buf, "RETR")) + info->file = fopen((char*)buf + 5, "rb"); + else if(info->canReceive) + info->file = fopen((char*)buf + 5, "wb"); + if(info->file) + { + IPPrintf(socket, "150 File ready\r\n"); + if(strstr((char*)buf, "RETR")) + socketOut = IPOpen(IP_MODE_TCP, info->ip, info->port, FtpdSender); + else + socketOut = IPOpen(IP_MODE_TCP, info->ip, info->port, FtpdReceiver); + if(socketOut) + socketOut->userPtr = info; + } + else + { + IPPrintf(socket, "500 Error\r\n"); + } + } + else if(strstr((char*)buf, "QUIT")) + { + if(socket->userPtr) + free(socket->userPtr); + socket->userPtr = (void*)-1; + IPPrintf(socket, "221 Bye\r\n"); + IPClose(socket); + } + else if(bytes) + { + IPPrintf(socket, "500 Error\r\n"); + } +} + + +void FtpdInit(int UseFiles) +{ + (void)UseFiles; + IPOpen(IP_MODE_TCP, 0, 21, FtpdServer); +} + + +//******************* FTP Client ************************ + +typedef struct { + uint32 ip, port; + char user[80], passwd[80], filename[80]; + uint8 *buf; + int size, bytes, send, state; +} FtpInfo; + + +static void FtpCallbackTransfer(IPSocket *socket) +{ + int bytes, state = socket->state; + FtpInfo *info = (FtpInfo*)socket->userPtr; + + //printf("FtpCallbackTransfer\n"); + if(info == NULL) + return; + bytes = info->size - info->bytes; + if(info->send == 0) + bytes = IPRead(socket, info->buf + info->bytes, bytes); + else + bytes = IPWrite(socket, info->buf + info->bytes, bytes); + info->bytes += bytes; + if(info->bytes == info->size || (bytes == 0 && state > IP_TCP)) + { + socket->userFunc(info->buf, info->bytes); + free(info); + socket->userPtr = NULL; + IPClose(socket); + } +} + + +static void FtpCallback(IPSocket *socket) +{ + char buf[600]; + FtpInfo *info = (FtpInfo*)socket->userPtr; + int bytes, value; + + bytes = IPRead(socket, (uint8*)buf, sizeof(buf)-1); + if(bytes == 0) + return; + buf[bytes] = 0; + sscanf(buf, "%d", &value); + if(bytes > 2) + buf[bytes-2] = 0; + //printf("FtpCallback(%d:%s)\n", socket->userData, buf); + if(value / 100 != 2 && value / 100 != 3) + return; + buf[0] = 0; + switch(socket->userData) { + case 0: + sprintf(buf, "USER %s\r\n", info->user); + socket->userData = 1; + break; + case 1: + sprintf(buf, "PASS %s\r\n", info->passwd); + socket->userData = 2; + if(value == 331) + break; //possible fall-through + case 2: + sprintf(buf, "PORT %d,%d,%d,%d,%d,%d\r\n", + info->ip >> 24, (uint8)(info->ip >> 16), + (uint8)(info->ip >> 8), (uint8)info->ip, + (uint8)(info->port >> 8), (uint8)info->port); + socket->userData = 3; + break; + case 3: + if(info->send == 0) + sprintf(buf, "RETR %s\r\n", info->filename); + else + sprintf(buf, "STOR %s\r\n", info->filename); + socket->userData = 4; + break; + case 4: + sprintf(buf, "QUIT\r\n"); + socket->userData = 9; + break; + } + IPWrite(socket, (uint8*)buf, strlen(buf)); + IPWriteFlush(socket); + if(socket->userData == 9) + IPClose(socket); +} + + +IPSocket *FtpTransfer(uint32 ip, char *user, char *passwd, + char *filename, uint8 *buf, int size, + int send, void (*callback)(uint8 *data, int size)) +{ + IPSocket *socket, *socketTransfer; + FtpInfo *info; + uint8 *ptr; + info = (FtpInfo*)malloc(sizeof(FtpInfo)); + if(info == NULL) + return NULL; + strncpy(info->user, user, 80); + strncpy(info->passwd, passwd, 80); + strncpy(info->filename, filename, 80); + info->buf = buf; + info->size = size; + info->send = send; + info->bytes = 0; + info->state = 0; + info->port = 2000; + socketTransfer = IPOpen(IP_MODE_TCP, 0, info->port, FtpCallbackTransfer); + socketTransfer->userPtr = info; + socketTransfer->userFunc = callback; + socket = IPOpen(IP_MODE_TCP, ip, 21, FtpCallback); + socket->userPtr = info; + socket->userFunc = callback; + ptr = socket->headerSend; + info->ip = IPAddressSelf(); + return socket; +} + + +//******************* TFTP Server ************************ + + +static void TftpdCallback(IPSocket *socket) +{ + unsigned char buf[512+4]; + int bytes, blockNum; + FILE *file = (FILE*)socket->userPtr; + bytes = IPRead(socket, buf, sizeof(buf)); + //printf("TfptdCallback bytes=%d\n", bytes); + if(bytes < 4 || buf[0]) + return; + if(buf[1] == 1) //RRQ = Read Request + { + if(file) + fclose(file); + file = fopen((char*)buf+2, "rb"); + socket->userPtr = file; + if(file == NULL) + { + buf[0] = 0; + buf[1] = 5; //ERROR + buf[2] = 0; + buf[3] = 0; + buf[4] = 'X'; //Error string + buf[5] = 0; + IPWrite(socket, buf, 6); + return; + } + } + if(buf[1] == 1 || buf[1] == 4) //ACK + { + if(file == NULL) + return; + if(buf[1] == 1) + blockNum = 0; + else + blockNum = (buf[2] << 8) | buf[3]; + ++blockNum; + buf[0] = 0; + buf[1] = 3; //DATA + buf[2] = (uint8)(blockNum >> 8); + buf[3] = (uint8)blockNum; + fseek(file, (blockNum-1)*512, 0); + bytes = fread(buf+4, 1, 512, file); + IPWrite(socket, buf, bytes+4); + } +} + + +void TftpdInit(void) +{ + IPSocket *socket; + socket = IPOpen(IP_MODE_UDP, 0, 69, TftpdCallback); +} + + +//******************* TFTP Client ************************ + + +static void TftpCallback(IPSocket *socket) +{ + unsigned char buf[512+4]; + int bytes, blockNum, length; + + bytes = IPRead(socket, buf, sizeof(buf)); + if(bytes < 4 || buf[0]) + return; + blockNum = (buf[2] << 8) | buf[3]; + length = blockNum * 512 - 512 + bytes - 4; + //printf("TftpCallback(%d,%d)\n", buf[1], blockNum); + if(length > (int)socket->userData) + { + bytes -= length - (int)socket->userData; + length = (int)socket->userData; + } + if(buf[1] == 3) //DATA + { + memcpy((uint8*)socket->userPtr + blockNum * 512 - 512, buf+4, bytes-4); + buf[1] = 4; //ACK + IPWrite(socket, buf, 4); + if(bytes-4 < 512) + { + socket->userFunc(socket->userPtr, length); + IPClose(socket); + } + } +} + + +IPSocket *TftpTransfer(uint32 ip, char *filename, uint8 *buffer, int size, + void (*callback)(uint8 *data, int bytes)) +{ + IPSocket *socket; + uint8 buf[512+4]; + int bytes; + socket = IPOpen(IP_MODE_UDP, ip, 69, TftpCallback); + socket->userPtr = buffer; + socket->userData = size; + socket->userFunc = callback; + buf[0] = 0; + buf[1] = 1; //read + strcpy((char*)buf+2, filename); + bytes = strlen(filename); + strcpy((char*)buf+bytes+3, "octet"); + IPWrite(socket, buf, bytes+9); + return socket; +} + + +//******************* Telnet Server ************************ + +#define COMMAND_BUFFER_SIZE 80 +#define COMMAND_BUFFER_COUNT 10 +static char CommandHistory[400]; +static char *CommandPtr[COMMAND_BUFFER_COUNT]; +static int CommandIndex; + +typedef void (*ConsoleFunc)(IPSocket *socket, char *argv[]); +typedef struct { + char *name; + ConsoleFunc func; +} TelnetFunc_t; +static TelnetFunc_t *TelnetFuncList; + + +static void TelnetServer(IPSocket *socket) +{ + uint8 buf[COMMAND_BUFFER_SIZE+4]; + char bufOut[32]; + int bytes, i, j, k, length, found; + char *ptr, *command = socket->userPtr; + char *argv[10]; + + if(socket->state > IP_TCP) + return; + for(;;) + { + bytes = IPRead(socket, buf, sizeof(buf)-1); + if(command == NULL) + { + socket->userPtr = command = (char*)malloc(COMMAND_BUFFER_SIZE); + if(command == NULL) + { + IPClose(socket); + return; + } + socket->timeoutReset = 300; + buf[0] = 255; //IAC + buf[1] = 251; //WILL + buf[2] = 3; //suppress go ahead + buf[3] = 255; //IAC + buf[4] = 251; //WILL + buf[5] = 1; //echo + strcpy((char*)buf+6, "Welcome to Plasma.\r\n-> "); + IPWrite(socket, buf, 6+23); + IPWriteFlush(socket); + command[0] = 0; + return; + } + if(bytes == 0) + return; + socket->dontFlush = 0; + buf[bytes] = 0; + length = (int)strlen(command); + for(j = 0; j < bytes; ++j) + { + if(buf[j] == 255) + return; + if(buf[j] == 8 || (buf[j] == 27 && buf[j+2] == 'D')) + { + if(buf[j] == 27) + j += 2; + if(length) + { + // Backspace + command[--length] = 0; + bufOut[0] = 8; + bufOut[1] = ' '; + bufOut[2] = 8; + IPWrite(socket, (uint8*)bufOut, 3); + } + } + else if(buf[j] == 27) + { + // Command History + if(buf[j+2] == 'A') + { + if(++CommandIndex > COMMAND_BUFFER_COUNT) + CommandIndex = COMMAND_BUFFER_COUNT; + } + else if(buf[j+2] == 'B') + { + if(--CommandIndex < 0) + CommandIndex = 0; + } + else + return; + bufOut[0] = 8; + bufOut[1] = ' '; + bufOut[2] = 8; + for(i = 0; i < length; ++i) + IPWrite(socket, (uint8*)bufOut, 3); + command[0] = 0; + if(CommandIndex && CommandPtr[CommandIndex-1]) + strncat(command, CommandPtr[CommandIndex-1], COMMAND_BUFFER_SIZE-1); + length = (int)strlen(command); + IPWrite(socket, (uint8*)command, length); + j += 2; + } + else + { + if(buf[j] == 0) + buf[j] = '\n'; //Linux support + if(length < COMMAND_BUFFER_SIZE-4 || (length < + COMMAND_BUFFER_SIZE-2 && (buf[j] == '\r' || buf[j] == '\n'))) + { + IPWrite(socket, buf+j, 1); + command[length] = buf[j]; + command[++length] = 0; + } + } + ptr = strstr(command, "\r\n"); + if(ptr) + { + // Save command in CommandHistory + ptr[0] = 0; + length = (int)strlen(command); + if(length == 0) + { + IPPrintf(socket, "-> "); + continue; + } + if(length < COMMAND_BUFFER_SIZE) + { + memmove(CommandHistory + length + 1, CommandHistory, + sizeof(CommandHistory) - length - 1); + strcpy(CommandHistory, command); + CommandHistory[sizeof(CommandHistory)-1] = 0; + for(i = COMMAND_BUFFER_COUNT-2; i >= 0; --i) + { + if(CommandPtr[i] == NULL || CommandPtr[i] + length + 1 >= + CommandHistory + sizeof(CommandHistory)) + CommandPtr[i+1] = NULL; + else + CommandPtr[i+1] = CommandPtr[i] + length + 1; + } + CommandPtr[0] = CommandHistory; + } + + //Start command + for(i = 0; i < 10; ++i) + argv[i] = ""; + i = 0; + argv[i++] = command; + for(ptr = command; *ptr && i < 10; ++ptr) + { + if(*ptr == ' ') + { + *ptr = 0; + argv[i++] = ptr + 1; + } + } + if(argv[0][0] == 0) + { + IPPrintf(socket, "-> "); + continue; + } + found = 0; + for(i = 0; TelnetFuncList[i].name; ++i) + { + if(strcmp(command, TelnetFuncList[i].name) == 0 && + TelnetFuncList[i].func) + { + found = 1; + for(k = 1; k < 10; ++k) + { + if(argv[k][0] == '>' && argv[k][1]) //stdout to file? + { + socket->fileOut = fopen(&argv[k][1], "a"); + argv[k] = ""; + } + if(argv[k][0] == '<' && argv[k][1]) //stdin from file? + { + socket->fileIn = fopen(&argv[k][1], "r"); + argv[k] = ""; + } + } + TelnetFuncList[i].func(socket, argv); + if(socket->fileOut) + { + fwrite("\r\n", 1, 2, socket->fileOut); + fclose(socket->fileOut); + } + socket->fileOut = NULL; + break; + } + } +#ifdef DLL_SETUP + if(found == 0) + { + strcpy((char*)buf, "/flash/bin/"); + strcat((char*)buf, argv[0]); + argv[0] = (char*)buf; + ConsoleRun(socket, argv); + } +#endif + if(socket->state > IP_TCP) + return; + command[0] = 0; + length = 0; + CommandIndex = 0; + if(socket->dontFlush == 0) + IPPrintf(socket, "\r\n-> "); + } //command entered + } //bytes + IPWriteFlush(socket); + } +} + + +void TelnetInit(TelnetFunc_t *funcList) +{ + IPSocket *socket; + TelnetFuncList = funcList; + socket = IPOpen(IP_MODE_TCP, 0, 23, TelnetServer); +} + + +//******************* Console ************************ + +#define STORAGE_SIZE 1024*64 +static uint8 *myStorage; +static IPSocket *socketTelnet; +static char storageFilename[60]; + + +static void ConsoleHelp(IPSocket *socket, char *argv[]) +{ + char buf[200]; + int i; + (void)argv; + strcpy(buf, "Commands: "); + for(i = 0; TelnetFuncList[i].name; ++i) + { + if(TelnetFuncList[i].func) + { + if(i) + strcat(buf, ", "); + strcat(buf, TelnetFuncList[i].name); + } + } + IPPrintf(socket, buf); +} + + +static void ConsoleExit(IPSocket *socket, char *argv[]) +{ + free(argv[0]); + socket->userPtr = NULL; + IPClose(socket); +} + + +static void ConsoleCat(IPSocket *socket, char *argv[]) +{ + FILE *file; + uint8 buf[200]; + int bytes; + + file = fopen(argv[1], "r"); + if(file == NULL) + return; + for(;;) + { + bytes = fread(buf, 1, sizeof(buf), file); + if(bytes == 0) + break; + IPWrite(socket, buf, bytes); + } + fclose(file); +} + + +static void ConsoleCp(IPSocket *socket, char *argv[]) +{ + FILE *fileIn, *fileOut; + uint8 buf[200]; + int bytes; + (void)socket; + + fileIn = fopen(argv[1], "r"); + if(fileIn == NULL) + return; + fileOut = fopen(argv[2], "w"); + if(fileOut) + { + for(;;) + { + bytes = fread(buf, 1, sizeof(buf), fileIn); + if(bytes == 0) + break; + fwrite(buf, 1, bytes, fileOut); + } + fclose(fileOut); + } + fclose(fileIn); +} + + +static void ConsoleRm(IPSocket *socket, char *argv[]) +{ + (void)socket; + OS_fdelete(argv[1]); +} + + +static void ConsoleMkdir(IPSocket *socket, char *argv[]) +{ + (void)socket; + OS_fmkdir(argv[1]); +} + + +static void ConsoleLs(IPSocket *socket, char *argv[]) +{ + FILE *file; + char buf[200], buf2[80]; + int bytes, width; + + file = fopen(argv[1], "r"); + if(file == NULL) + return; + width = 0; + for(;;) + { + bytes = OS_fdir(file, buf); + if(bytes) + break; + if(buf[0] == 255) + continue; + bytes = OS_flength(buf); + sprintf(buf2, "%s:%d ", buf, bytes); + bytes = strlen(buf2); + bytes -= bytes % 20; + buf2[bytes] = 0; + width += bytes; + if(width == 80) + --bytes; + if(width > 80) + { + IPPrintf(socket, "\n"); + width = bytes; + } + IPPrintf(socket, "%s", buf2); + } + fclose(file); +} + + +#ifdef INCLUDE_FLASH +static void ConsoleFlashErase(IPSocket *socket, char *argv[]) +{ + int bytes; + (void)argv; + IPPrintf(socket, "\r\nErasing"); + for(bytes = 1024*128; bytes < 1024*1024*16; bytes += 1024*128) + { + IPPrintf(socket, "."); + FlashErase(bytes); + } + IPPrintf(socket, "\r\nMust Reboot\r\n"); + OS_ThreadSleep(OS_WAIT_FOREVER); +} +#endif + + +static void ConsoleMath(IPSocket *socket, char *argv[]) +{ + int v1, v2, ch; + if(argv[3][0] == 0) + { + IPPrintf(socket, "Usage: math \r\n"); + return; + } + v1 = atoi(argv[1]); + ch = argv[2][0]; + v2 = atoi(argv[3]); + if(ch == '+') + v1 += v2; + else if(ch == '-') + v1 -= v2; + else if(ch == '*') + v1 *= v2; + else if(ch == '/') + { + if(v2 != 0) + v1 /= v2; + } + IPPrintf(socket, "%d", v1); +} + + +static void PingCallback(IPSocket *socket) +{ + IPSocket *socket2 = socket->userPtr; + IPClose(socket); + if(socket2) + IPPrintf(socket2, "Ping Reply"); + else + printf("Ping Reply\n"); +} + + +static void DnsResultCallback(IPSocket *socket, uint32 ip, void *arg) +{ + char buf[COMMAND_BUFFER_SIZE]; + IPSocket *socketTelnet = arg; + IPSocket *socketPing; + (void)socket; + + sprintf(buf, "ip=%d.%d.%d.%d\r\n", + (uint8)(ip >> 24), (uint8)(ip >> 16), (uint8)(ip >> 8), (uint8)ip); + IPPrintf(socketTelnet, buf); + socketPing = IPOpen(IP_MODE_PING, ip, 0, PingCallback); + socketPing->userPtr = socketTelnet; + buf[0] = 'A'; + IPWrite(socketPing, (uint8*)buf, 1); +} + + +static void ConsolePing(IPSocket *socket, char *argv[]) +{ + int ip0, ip1, ip2, ip3; + + if('0' <= argv[1][0] && argv[1][0] <= '9') + { + sscanf(argv[1], "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3); + ip0 = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; + DnsResultCallback(socket, ip0, socket); + } + else + { + IPResolve(argv[1], DnsResultCallback, socket); + IPPrintf(socket, "Sent DNS request"); + } +} + + +static void ConsoleTransferDone(uint8 *data, int length) +{ + FILE *file; + IPPrintf(socketTelnet, "Transfer Done"); + file = fopen(storageFilename, "w"); + if(file) + { + fwrite(data, 1, length, file); + fclose(file); + } + if(myStorage) + free(myStorage); + myStorage = NULL; +} + + +static void ConsoleFtp(IPSocket *socket, char *argv[]) +{ + int ip0, ip1, ip2, ip3; + if(argv[1][0] == 0) + { + IPPrintf(socket, "ftp #.#.#.# User Password File"); + return; + } + sscanf(argv[1], "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3); + ip0 = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; + socketTelnet = socket; + if(myStorage == NULL) + myStorage = (uint8*)malloc(STORAGE_SIZE); + if(myStorage == NULL) + return; + strcpy(storageFilename, argv[4]); + FtpTransfer(ip0, argv[2], argv[3], argv[4], myStorage, STORAGE_SIZE-1, + 0, ConsoleTransferDone); +} + + +static void ConsoleTftp(IPSocket *socket, char *argv[]) +{ + int ip0, ip1, ip2, ip3; + if(argv[1][0] == 0) + { + IPPrintf(socket, "tftp #.#.#.# File"); + return; + } + sscanf(argv[1], "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3); + ip0 = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; + socketTelnet = socket; + if(myStorage == NULL) + myStorage = (uint8*)malloc(STORAGE_SIZE); + if(myStorage == NULL) + return; + strcpy(storageFilename, argv[2]); + TftpTransfer(ip0, argv[2], myStorage, STORAGE_SIZE-1, ConsoleTransferDone); +} + + +static void ConsoleMkfile(IPSocket *socket, char *argv[]) +{ + OS_FILE *file; + (void)argv; + file = fopen("myfile.txt", "w"); + fwrite("Hello World!", 1, 12, file); + fclose(file); + IPPrintf(socket, "Created myfile.txt"); +} + + +static void ConsoleUptime(IPSocket *socket, char *argv[]) +{ + int days, hours, minutes, seconds; + (void)argv; + //ticks per sec = 25E6/2^18 = 95.36743 -> 10.48576 ms/tick + seconds = OS_ThreadTime() / 95; + minutes = seconds / 60 % 60; + hours = seconds / 3600 % 24; + days = seconds / 3600 / 24; + seconds %= 60; + IPPrintf(socket, "%d days %2d:%2d:%2d\n", days, hours, minutes, seconds); +} + + +static void ConsoleDump(IPSocket *socket, char *argv[]) +{ + FILE *fileIn; + uint8 buf[16]; + int bytes, i, j; + + fileIn = fopen(argv[1], "r"); + if(fileIn == NULL) + return; + for(j = 0; j < 1024*1024*16; j += 16) + { + bytes = fread(buf, 1, 16, fileIn); + if(bytes == 0) + break; + IPPrintf(socket, "%8x ", j); + for(i = 0; i < bytes; ++i) + IPPrintf(socket, "%2x ", buf[i]); + for( ; i < 16; ++i) + IPPrintf(socket, " "); + for(i = 0; i < bytes; ++i) + { + if(isprint(buf[i])) + IPPrintf(socket, "%c", buf[i]); + else + IPPrintf(socket, "."); + } + IPPrintf(socket, "\n"); + } + fclose(fileIn); +} + + +static void ConsoleGrep(IPSocket *socket, char *argv[]) +{ + FILE *fileIn; + char buf[200]; + int bytes; + char *ptr, *ptrEnd; + + if(argv[1][0] == 0 || argv[2][0] == 0) + { + IPPrintf(socket, "Usage: grep pattern file\n"); + return; + } + fileIn = fopen(argv[2], "r"); + if(fileIn == NULL) + return; + bytes = 0; + for(;;) + { + bytes += fread(buf + bytes, 1, sizeof(buf) - bytes - 1, fileIn); + if(bytes == 0) + break; + buf[bytes] = 0; + ptrEnd = strstr(buf, "\r"); + if(ptrEnd == NULL) + ptrEnd = strstr(buf, "\n"); + if(ptrEnd) + { + *ptrEnd = 0; + if(*++ptrEnd == '\n') + ++ptrEnd; + } + ptr = strstr(buf, argv[1]); + if(ptr) + IPPrintf(socket, "%s\n", buf); + if(ptrEnd) + { + bytes = strlen(ptrEnd); + memcpy(buf, ptrEnd, bytes); + } + else + { + bytes = 0; + } + } + fclose(fileIn); +} + + +#ifdef DLL_SETUP +#include "dll.h" + +static void ConsoleRun(IPSocket *socket, char *argv[]) +{ + FILE *file; + int bytes, i; + uint8 code[128]; + DllFunc funcPtr; + char *command, *ptr; + + if(strcmp(argv[0], "run") == 0) + ++argv; + file = fopen(argv[0], "r"); + if(file == NULL) + { + IPPrintf(socket, "Can't find %s", argv[0]); + return; + } + + bytes = fread(code, 1, sizeof(code), file); //load first 128 bytes + if(code[0] >= ' ') + { + socket->fileIn = file; //script file + fseek(file, 0, 0); + return; + } + + funcPtr = (DllFunc)code; + ptr = funcPtr(NULL); //determine load address + + memcpy(ptr, code, bytes); //copy to correct address + bytes += fread(ptr + bytes, 1, 1024*1024*8, file); + fclose(file); + printf("address=0x%x bytes=%d\n", (int)ptr, bytes); + funcPtr = (DllFunc)ptr; + funcPtr = (DllFunc)funcPtr(DllFuncList); //initialize DLL, find Start() + + //Register new command + command = argv[0]; + for(;;) + { + ptr = strstr(command, "/"); + if(ptr == NULL) + break; + command = ptr + 1; + } + for(i = 0; TelnetFuncList[i].name; ++i) + { + if(TelnetFuncList[i].name[0] == 0 || + strcmp(TelnetFuncList[i].name, command) == 0) + { + TelnetFuncList[i].name = (char*)malloc(40); + strcpy(TelnetFuncList[i].name, command); + TelnetFuncList[i].func = (ConsoleFunc)funcPtr; + break; + } + } + + socket->userFunc = socket->funcPtr; + funcPtr(socket, argv); +} + + +typedef struct NameValue_t { + struct NameValue_t *next; + void *value; + char name[1]; +} NameValue_t; + +//Find the value associated with the name +void *IPNameValue(const char *name, void *value) +{ + static NameValue_t *head; + NameValue_t *node; + for(node = head; node; node = node->next) + { + if(strcmp(node->name, name) == 0) + break; + } + if(node == NULL) + { + node = (NameValue_t*)malloc(sizeof(NameValue_t) + (int)strlen(name)); + if(node == NULL) + return NULL; + strcpy(node->name, name); + node->value = value; + node->next = head; + head = node; + } + if(value) + node->value = value; + return node->value; +} +#endif + + +#ifdef EDIT_FILE +extern void EditFile(IPSocket *socket, char *argv[]); +#endif + +static TelnetFunc_t MyFuncs[] = { + {"cat", ConsoleCat}, + {"cp", ConsoleCp}, + {"dump", ConsoleDump}, + {"exit", ConsoleExit}, +#ifdef INCLUDE_FLASH + {"flashErase", ConsoleFlashErase}, +#endif + {"ftp", ConsoleFtp}, + {"grep", ConsoleGrep}, + {"help", ConsoleHelp}, + {"ls", ConsoleLs}, + {"math", ConsoleMath}, + {"mkdir", ConsoleMkdir}, + {"mkfile", ConsoleMkfile}, + {"ping", ConsolePing}, + {"rm", ConsoleRm}, + {"tftp", ConsoleTftp}, + {"uptime", ConsoleUptime}, +#ifdef DLL_SETUP + {"run", ConsoleRun}, +#endif +#ifdef EDIT_FILE + {"edit", EditFile}, +#endif + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {"", NULL}, + {NULL, NULL} +}; + + +void ConsoleInit(void) +{ + FtpdInit(1); + TftpdInit(); + TelnetInit(MyFuncs); +} diff --git a/kernel/os_stubs.c b/kernel/os_stubs.c new file mode 100644 index 0000000..606dab1 --- /dev/null +++ b/kernel/os_stubs.c @@ -0,0 +1,71 @@ +/*-------------------------------------------------------------------- + * TITLE: OS stubs + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 2/18/08 + * FILENAME: os_stubs.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + *--------------------------------------------------------------------*/ +#include +#include "plasma.h" +#include "rtos.h" + +unsigned char *flash; +int beenInit; + + +void FlashRead(uint16 *dst, uint32 byteOffset, int bytes) +{ + if(beenInit == 0) + { + beenInit = 1; + flash = (unsigned char*)malloc(1024*1024*16); + memset(flash, 0xff, sizeof(flash)); + } + memcpy(dst, flash+byteOffset, bytes); +} + + +void FlashWrite(uint16 *src, uint32 byteOffset, int bytes) +{ + memcpy(flash+byteOffset, src, bytes); +} + + +void FlashErase(uint32 byteOffset) +{ + memset(flash+byteOffset, 0xff, 1024*128); +} + + +//Stub out RTOS functions +void UartPrintfCritical(const char *format, ...) {(void)format;} +uint32 OS_AsmInterruptEnable(uint32 state) {(void)state; return 0;} +void OS_Assert(void) {} +OS_Thread_t *OS_ThreadSelf(void) {return NULL;} +void OS_ThreadSleep(int ticks) {(void)ticks;} +uint32 OS_ThreadTime(void) {return 0;} +OS_Mutex_t *OS_MutexCreate(const char *name) {(void)name; return NULL; } +void OS_MutexDelete(OS_Mutex_t *semaphore) {(void)semaphore;} +void OS_MutexPend(OS_Mutex_t *semaphore) {(void)semaphore;} +void OS_MutexPost(OS_Mutex_t *semaphore) {(void)semaphore;} + +OS_MQueue_t *OS_MQueueCreate(const char *name, + int messageCount, + int messageBytes) +{(void)name;(void)messageCount;(void)messageBytes; return NULL;} + +void OS_MQueueDelete(OS_MQueue_t *mQueue) {(void)mQueue;} + +int OS_MQueueSend(OS_MQueue_t *mQueue, void *message) +{(void)mQueue;(void)message; return 0;} + +int OS_MQueueGet(OS_MQueue_t *mQueue, void *message, int ticks) +{(void)mQueue;(void)message;(void)ticks; return 0;} + +void OS_Job(void (*funcPtr)(), void *arg0, void *arg1, void *arg2) +{funcPtr(arg0, arg1, arg2);} + + diff --git a/kernel/rtos.c b/kernel/rtos.c new file mode 100644 index 0000000..3c03538 --- /dev/null +++ b/kernel/rtos.c @@ -0,0 +1,1508 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Real Time Operating System + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/17/05 + * FILENAME: rtos.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma Real Time Operating System + * Fully pre-emptive RTOS with support for: + * Heaps, Threads, Semaphores, Mutexes, Message Queues, and Timers. + * This file tries to be hardware independent except for calls to: + * MemoryRead() and MemoryWrite() for interrupts. + * Partial support for multiple CPUs using symmetric multiprocessing. + *--------------------------------------------------------------------*/ +#include "plasma.h" +#include "rtos.h" + +#define HEAP_MAGIC 0x1234abcd +#define THREAD_MAGIC 0x4321abcd +#define SEM_RESERVED_COUNT 2 +#define INFO_COUNT 4 +#define HEAP_COUNT 8 + + +/*************** Structures ***************/ +#ifdef WIN32 + #define setjmp _setjmp + //x86 registers + typedef struct jmp_buf2 { + uint32 Ebp, Ebx, Edi, Esi, sp, pc, extra[10]; + } jmp_buf2; +#elif defined(ARM_CPU) + //ARM registers + typedef struct jmp_buf2 { + uint32 r[13], sp, lr, pc, cpsr, extra[5]; + } jmp_buf2; +#else + //Plasma registers + typedef struct jmp_buf2 { + uint32 s[9], gp, sp, pc; + } jmp_buf2; +#endif + +typedef struct HeapNode_s { + struct HeapNode_s *next; + int size; +} HeapNode_t; + +struct OS_Heap_s { + uint32 magic; + const char *name; + OS_Semaphore_t *semaphore; + HeapNode_t *available; + HeapNode_t base; + struct OS_Heap_s *alternate; +}; +//typedef struct OS_Heap_s OS_Heap_t; + +typedef enum { + THREAD_PEND = 0, //Thread in semaphore's linked list + THREAD_READY = 1, //Thread in ThreadHead linked list + THREAD_RUNNING = 2 //Thread == ThreadCurrent[cpu] +} OS_ThreadState_e; + +struct OS_Thread_s { + const char *name; //Name of thread + OS_ThreadState_e state; //Pending, ready, or running + int cpuIndex; //Which CPU is running the thread + int cpuLock; //Lock the thread to a specific CPU + jmp_buf env; //Registers saved during context swap + OS_FuncPtr_t funcPtr; //First function called + void *arg; //Argument to first function called + uint32 priority; //Priority of thread (0=low, 255=high) + uint32 ticksTimeout; //Tick value when semaphore pend times out + void *info[INFO_COUNT]; //User storage + OS_Semaphore_t *semaphorePending; //Semaphore thread is blocked on + int returnCode; //Return value from semaphore pend + uint32 processId; //Process ID if using MMU + OS_Heap_t *heap; //Heap used if no heap specified + struct OS_Thread_s *next; //Linked list of threads by priority + struct OS_Thread_s *prev; + struct OS_Thread_s *nextTimeout; //Linked list of threads by timeout + struct OS_Thread_s *prevTimeout; + uint32 magic[1]; //Bottom of stack to detect stack overflow +}; +//typedef struct OS_Thread_s OS_Thread_t; + +struct OS_Semaphore_s { + const char *name; + struct OS_Thread_s *threadHead; //threads pending on semaphore + int count; +}; +//typedef struct OS_Semaphore_s OS_Semaphore_t; + +struct OS_Mutex_s { + OS_Semaphore_t *semaphore; + OS_Thread_t *thread; + int count; +}; +//typedef struct OS_Mutex_s OS_Mutex_t; + +struct OS_MQueue_s { + const char *name; + OS_Semaphore_t *semaphore; + int count, size, used, read, write; +}; +//typedef struct OS_MQueue_s OS_MQueue_t; + +struct OS_Timer_s { + const char *name; + struct OS_Timer_s *next, *prev; + uint32 ticksTimeout; + uint32 ticksRestart; + int active; + OS_TimerFuncPtr_t callback; + OS_MQueue_t *mqueue; + uint32 info; +}; +//typedef struct OS_Timer_s OS_Timer_t; + + +/*************** Globals ******************/ +static OS_Heap_t *HeapArray[HEAP_COUNT]; +static int InterruptInside[OS_CPU_COUNT]; +static int ThreadNeedReschedule[OS_CPU_COUNT]; +static OS_Thread_t *ThreadCurrent[OS_CPU_COUNT]; //Currently running thread(s) +static OS_Thread_t *ThreadHead; //Linked list of threads sorted by priority +static OS_Thread_t *TimeoutHead; //Linked list of threads sorted by timeout +static int ThreadSwapEnabled; +static uint32 ThreadTime; //Number of ~10ms ticks since reboot +static void *NeedToFree; //Closed but not yet freed thread +static OS_Semaphore_t SemaphoreReserved[SEM_RESERVED_COUNT]; +static OS_Semaphore_t *SemaphoreSleep; +static OS_Semaphore_t *SemaphoreRelease; +static OS_Semaphore_t *SemaphoreLock; +static OS_Semaphore_t *SemaphoreTimer; +static OS_Timer_t *TimerHead; //Linked list of timers sorted by timeout +static OS_FuncPtr_t Isr[32]; + + +/***************** Heap *******************/ +/******************************************/ +OS_Heap_t *OS_HeapCreate(const char *name, void *memory, uint32 size) +{ + OS_Heap_t *heap; + + assert(((uint32)memory & 3) == 0); + heap = (OS_Heap_t*)memory; + heap->magic = HEAP_MAGIC; + heap->name = name; + heap->semaphore = OS_SemaphoreCreate(name, 1); + heap->available = (HeapNode_t*)(heap + 1); + heap->available->next = &heap->base; + heap->available->size = (size - sizeof(OS_Heap_t)) / sizeof(HeapNode_t); + heap->base.next = heap->available; + heap->base.size = 0; + return heap; +} + + +/******************************************/ +void OS_HeapDestroy(OS_Heap_t *heap) +{ + OS_SemaphoreDelete(heap->semaphore); +} + + +/******************************************/ +//Modified from Kernighan & Ritchie "The C Programming Language" +void *OS_HeapMalloc(OS_Heap_t *heap, int bytes) +{ + HeapNode_t *node, *prevp; + int nunits; + + if(heap == NULL && OS_ThreadSelf()) + heap = OS_ThreadSelf()->heap; + if((uint32)heap < HEAP_COUNT) + heap = HeapArray[(int)heap]; + nunits = (bytes + sizeof(HeapNode_t) - 1) / sizeof(HeapNode_t) + 1; + OS_SemaphorePend(heap->semaphore, OS_WAIT_FOREVER); + prevp = heap->available; + for(node = prevp->next; ; prevp = node, node = node->next) + { + if(node->size >= nunits) //Big enough? + { + if(node->size == nunits) //Exactly + prevp->next = node->next; + else + { //Allocate tail end + node->size -= nunits; + node += node->size; + node->size = nunits; + } + heap->available = prevp; + node->next = (HeapNode_t*)heap; + OS_SemaphorePost(heap->semaphore); + return (void*)(node + 1); + } + if(node == heap->available) //Wrapped around free list + { + OS_SemaphorePost(heap->semaphore); + if(heap->alternate) + return OS_HeapMalloc(heap->alternate, bytes); + return NULL; + } + } +} + + +/******************************************/ +//Modified from K&R +void OS_HeapFree(void *block) +{ + OS_Heap_t *heap; + HeapNode_t *bp, *node; + + assert(block); + bp = (HeapNode_t*)block - 1; //point to block header + heap = (OS_Heap_t*)bp->next; + assert(heap->magic == HEAP_MAGIC); + if(heap->magic != HEAP_MAGIC) + return; + OS_SemaphorePend(heap->semaphore, OS_WAIT_FOREVER); + for(node = heap->available; !(node < bp && bp < node->next); node = node->next) + { + if(node >= node->next && (bp > node || bp < node->next)) + break; //freed block at start or end of area + } + + if(bp + bp->size == node->next) //join to upper + { + bp->size += node->next->size; + bp->next = node->next->next; + } + else + { + bp->next = node->next; + } + + if(node + node->size == bp) //join to lower + { + node->size += bp->size; + node->next = bp->next; + } + else + node->next = bp; + heap->available = node; + OS_SemaphorePost(heap->semaphore); +} + + +/******************************************/ +void OS_HeapAlternate(OS_Heap_t *heap, OS_Heap_t *alternate) +{ + heap->alternate = alternate; +} + + +/******************************************/ +void OS_HeapRegister(void *index, OS_Heap_t *heap) +{ + if((uint32)index < HEAP_COUNT) + HeapArray[(int)index] = heap; +} + + + +/***************** Thread *****************/ +/******************************************/ +//Linked list of threads sorted by priority +//The listed list is either ThreadHead (ready to run threads not including +//the currently running thread) or a list of threads waiting on a semaphore. +//Must be called with interrupts disabled +static void OS_ThreadPriorityInsert(OS_Thread_t **head, OS_Thread_t *thread) +{ + OS_Thread_t *node, *prev; + + prev = NULL; + for(node = *head; node; node = node->next) + { + if(node->priority < thread->priority) + break; + prev = node; + } + + if(prev == NULL) + { + thread->next = *head; + thread->prev = NULL; + if(*head) + (*head)->prev = thread; + *head = thread; + } + else + { + if(prev->next) + prev->next->prev = thread; + thread->next = prev->next; + thread->prev = prev; + prev->next = thread; + } + assert(ThreadHead); + thread->state = THREAD_READY; +} + + +/******************************************/ +//Must be called with interrupts disabled +static void OS_ThreadPriorityRemove(OS_Thread_t **head, OS_Thread_t *thread) +{ + assert(thread->magic[0] == THREAD_MAGIC); //check stack overflow + if(thread->prev == NULL) + *head = thread->next; + else + thread->prev->next = thread->next; + if(thread->next) + thread->next->prev = thread->prev; + thread->next = NULL; + thread->prev = NULL; +} + + +/******************************************/ +//Linked list of threads sorted by timeout value +//Must be called with interrupts disabled +static void OS_ThreadTimeoutInsert(OS_Thread_t *thread) +{ + OS_Thread_t *node, *prev; + int diff; + + prev = NULL; + for(node = TimeoutHead; node; node = node->nextTimeout) + { + diff = thread->ticksTimeout - node->ticksTimeout; + if(diff <= 0) + break; + prev = node; + } + + if(prev == NULL) + { + thread->nextTimeout = TimeoutHead; + thread->prevTimeout = NULL; + if(TimeoutHead) + TimeoutHead->prevTimeout = thread; + TimeoutHead = thread; + } + else + { + if(prev->nextTimeout) + prev->nextTimeout->prevTimeout = thread; + thread->nextTimeout = prev->nextTimeout; + thread->prevTimeout = prev; + prev->nextTimeout = thread; + } +} + + +/******************************************/ +//Must be called with interrupts disabled +static void OS_ThreadTimeoutRemove(OS_Thread_t *thread) +{ + if(thread->prevTimeout == NULL && TimeoutHead != thread) + return; //not in list + if(thread->prevTimeout == NULL) + TimeoutHead = thread->nextTimeout; + else + thread->prevTimeout->nextTimeout = thread->nextTimeout; + if(thread->nextTimeout) + thread->nextTimeout->prevTimeout = thread->prevTimeout; + thread->nextTimeout = NULL; + thread->prevTimeout = NULL; +} + + +/******************************************/ +//Loads highest priority thread from the ThreadHead linked list +//The currently running thread isn't in the ThreadHead list +//Must be called with interrupts disabled +static void OS_ThreadReschedule(int roundRobin) +{ + OS_Thread_t *threadNext, *threadCurrent; + int rc, cpuIndex = OS_CpuIndex(); + + if(ThreadSwapEnabled == 0 || InterruptInside[cpuIndex]) + { + ThreadNeedReschedule[cpuIndex] |= 2 + roundRobin; //Reschedule later + return; + } + ThreadNeedReschedule[cpuIndex] = 0; + + //Determine which thread should run + threadNext = ThreadHead; + while(threadNext && threadNext->cpuLock != -1 && + threadNext->cpuLock != cpuIndex) + threadNext = threadNext->next; //Skip CPU locked threads + if(threadNext == NULL) + return; + threadCurrent = ThreadCurrent[cpuIndex]; + + if(threadCurrent == NULL || + threadCurrent->state == THREAD_PEND || + threadCurrent->priority < threadNext->priority || + (roundRobin && threadCurrent->priority == threadNext->priority)) + { + //Swap threads + ThreadCurrent[cpuIndex] = threadNext; + if(threadCurrent) + { + assert(threadCurrent->magic[0] == THREAD_MAGIC); //check stack overflow + if(threadCurrent->state == THREAD_RUNNING) + OS_ThreadPriorityInsert(&ThreadHead, threadCurrent); + rc = setjmp(threadCurrent->env); //ANSI C call to save registers + if(rc) + return; //Returned from longjmp() + } + + //Remove the new running thread from the ThreadHead linked list + threadNext = ThreadCurrent[OS_CpuIndex()]; //removed warning + assert(threadNext->state == THREAD_READY); + OS_ThreadPriorityRemove(&ThreadHead, threadNext); + threadNext->state = THREAD_RUNNING; + threadNext->cpuIndex = OS_CpuIndex(); + longjmp(threadNext->env, 1); //ANSI C call to restore registers + } +} + + +/******************************************/ +void OS_ThreadCpuLock(OS_Thread_t *thread, int cpuIndex) +{ + thread->cpuLock = cpuIndex; + if(thread == OS_ThreadSelf() && cpuIndex != (int)OS_CpuIndex()) + OS_ThreadSleep(1); +} + + +/******************************************/ +static void OS_ThreadInit(void *arg) +{ + uint32 cpuIndex = OS_CpuIndex(); + (void)arg; + + OS_CriticalEnd(1); + ThreadCurrent[cpuIndex]->funcPtr(ThreadCurrent[cpuIndex]->arg); + OS_ThreadExit(); +} + + +/******************************************/ +//Stops warning "argument X might be clobbered by `longjmp'" +static void OS_ThreadRegsInit(jmp_buf env) +{ + setjmp(env); //ANSI C call to save registers +} + + +/******************************************/ +OS_Thread_t *OS_ThreadCreate(const char *name, + OS_FuncPtr_t funcPtr, + void *arg, + uint32 priority, + uint32 stackSize) +{ + OS_Thread_t *thread; + uint8 *stack; + jmp_buf2 *env; + uint32 state; + + OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER); + if(NeedToFree) + OS_HeapFree(NeedToFree); + NeedToFree = NULL; + OS_SemaphorePost(SemaphoreRelease); + + if(stackSize == 0) + stackSize = STACK_SIZE_DEFAULT; + if(stackSize < STACK_SIZE_MINIMUM) + stackSize = STACK_SIZE_MINIMUM; + thread = (OS_Thread_t*)OS_HeapMalloc(NULL, sizeof(OS_Thread_t) + stackSize); + assert(thread); + if(thread == NULL) + return NULL; + memset(thread, 0, sizeof(OS_Thread_t)); + stack = (uint8*)(thread + 1); + memset(stack, 0xcd, stackSize); + + thread->name = name; + thread->state = THREAD_READY; + thread->cpuLock = -1; + thread->funcPtr = funcPtr; + thread->arg = arg; + thread->priority = priority; + thread->semaphorePending = NULL; + thread->returnCode = 0; + if(OS_ThreadSelf()) + { + thread->processId = OS_ThreadSelf()->processId; + thread->heap = OS_ThreadSelf()->heap; + } + else + { + thread->processId = 0; + thread->heap = NULL; + } + thread->next = NULL; + thread->prev = NULL; + thread->nextTimeout = NULL; + thread->prevTimeout = NULL; + thread->magic[0] = THREAD_MAGIC; + + OS_ThreadRegsInit(thread->env); + env = (jmp_buf2*)thread->env; + env->sp = (uint32)stack + stackSize - 24; //minimum stack frame size + env->pc = (uint32)OS_ThreadInit; + + //Add thread to linked list of ready to run threads + state = OS_CriticalBegin(); + OS_ThreadPriorityInsert(&ThreadHead, thread); + OS_ThreadReschedule(0); //run highest priority thread + OS_CriticalEnd(state); + return thread; +} + + +/******************************************/ +void OS_ThreadExit(void) +{ + uint32 state, cpuIndex = OS_CpuIndex(); + + for(;;) + { + //Free the memory for closed but not yet freed threads + OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER); + if(NeedToFree) + OS_HeapFree(NeedToFree); + NeedToFree = NULL; + OS_SemaphorePost(SemaphoreRelease); + + state = OS_CriticalBegin(); + if(NeedToFree) + { + OS_CriticalEnd(state); + continue; + } + ThreadCurrent[cpuIndex]->state = THREAD_PEND; + NeedToFree = ThreadCurrent[cpuIndex]; + OS_ThreadReschedule(0); + OS_CriticalEnd(state); + } +} + + +/******************************************/ +//Return currently running thread +OS_Thread_t *OS_ThreadSelf(void) +{ + return ThreadCurrent[OS_CpuIndex()]; +} + + +/******************************************/ +//Sleep for ~10 msecs ticks +void OS_ThreadSleep(int ticks) +{ + OS_SemaphorePend(SemaphoreSleep, ticks); +} + + +/******************************************/ +//Return the number of ~10 msecs ticks since reboot +uint32 OS_ThreadTime(void) +{ + return ThreadTime; +} + + +/******************************************/ +//Save thread unique values +void OS_ThreadInfoSet(OS_Thread_t *thread, uint32 index, void *Info) +{ + if(index < INFO_COUNT) + thread->info[index] = Info; +} + + +/******************************************/ +void *OS_ThreadInfoGet(OS_Thread_t *thread, uint32 index) +{ + if(index < INFO_COUNT) + return thread->info[index]; + return NULL; +} + + +/******************************************/ +uint32 OS_ThreadPriorityGet(OS_Thread_t *thread) +{ + return thread->priority; +} + + +/******************************************/ +void OS_ThreadPrioritySet(OS_Thread_t *thread, uint32 priority) +{ + uint32 state; + state = OS_CriticalBegin(); + thread->priority = priority; + if(thread->state == THREAD_READY) + { + OS_ThreadPriorityRemove(&ThreadHead, thread); + OS_ThreadPriorityInsert(&ThreadHead, thread); + OS_ThreadReschedule(0); + } + OS_CriticalEnd(state); +} + + +/******************************************/ +void OS_ThreadProcessId(OS_Thread_t *thread, uint32 processId, OS_Heap_t *heap) +{ + thread->processId = processId; + thread->heap = heap; +} + + +/******************************************/ +//Must be called with interrupts disabled every ~10 msecs +//Will wake up threads that have timed out waiting on a semaphore +void OS_ThreadTick(void *Arg) +{ + OS_Thread_t *thread; + OS_Semaphore_t *semaphore; + int diff; + (void)Arg; + + ++ThreadTime; //Number of ~10 msec ticks since reboot + while(TimeoutHead) + { + thread = TimeoutHead; + diff = ThreadTime - thread->ticksTimeout; + if(diff < 0) + break; + + //The thread has timed out waiting for a semaphore + OS_ThreadTimeoutRemove(thread); + semaphore = thread->semaphorePending; + ++semaphore->count; + thread->semaphorePending = NULL; + thread->returnCode = -1; + OS_ThreadPriorityRemove(&semaphore->threadHead, thread); + OS_ThreadPriorityInsert(&ThreadHead, thread); + } + OS_ThreadReschedule(1); //Run highest priority thread +} + + + +/***************** Semaphore **************/ +/******************************************/ +//Create a counting semaphore +OS_Semaphore_t *OS_SemaphoreCreate(const char *name, uint32 count) +{ + OS_Semaphore_t *semaphore; + static int semCount = 0; + + if(semCount < SEM_RESERVED_COUNT) + semaphore = &SemaphoreReserved[semCount++]; //Heap not ready yet + else + semaphore = (OS_Semaphore_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Semaphore_t)); + assert(semaphore); + if(semaphore == NULL) + return NULL; + + semaphore->name = name; + semaphore->threadHead = NULL; + semaphore->count = count; + return semaphore; +} + + +/******************************************/ +void OS_SemaphoreDelete(OS_Semaphore_t *semaphore) +{ + while(semaphore->threadHead) + OS_SemaphorePost(semaphore); + OS_HeapFree(semaphore); +} + + +/******************************************/ +//Sleep the number of ticks (~10ms) until the semaphore is acquired +int OS_SemaphorePend(OS_Semaphore_t *semaphore, int ticks) +{ + uint32 state, cpuIndex; + OS_Thread_t *thread; + int returnCode=0; + + assert(semaphore); + assert(InterruptInside[OS_CpuIndex()] == 0); + state = OS_CriticalBegin(); //Disable interrupts + if(--semaphore->count < 0) + { + //Semaphore not available + if(ticks == 0) + { + ++semaphore->count; + OS_CriticalEnd(state); + return -1; + } + + //Need to sleep until the semaphore is available + cpuIndex = OS_CpuIndex(); + thread = ThreadCurrent[cpuIndex]; + assert(thread); + thread->semaphorePending = semaphore; + thread->ticksTimeout = ticks + OS_ThreadTime(); + + //FYI: The current thread isn't in the ThreadHead linked list + //Place the thread into a sorted linked list of pending threads + OS_ThreadPriorityInsert(&semaphore->threadHead, thread); + thread->state = THREAD_PEND; + if(ticks != OS_WAIT_FOREVER) + OS_ThreadTimeoutInsert(thread); //Check every ~10ms for timeouts + assert(ThreadHead); + OS_ThreadReschedule(0); //Run highest priority thread + returnCode = thread->returnCode; //Will be -1 if timed out + } + OS_CriticalEnd(state); //Re-enable interrupts + return returnCode; +} + + +/******************************************/ +//Release a semaphore and possibly wake up a blocked thread +void OS_SemaphorePost(OS_Semaphore_t *semaphore) +{ + uint32 state; + OS_Thread_t *thread; + + assert(semaphore); + state = OS_CriticalBegin(); + if(++semaphore->count <= 0) + { + //Wake up a thread that was waiting for this semaphore + thread = semaphore->threadHead; + OS_ThreadTimeoutRemove(thread); + OS_ThreadPriorityRemove(&semaphore->threadHead, thread); + OS_ThreadPriorityInsert(&ThreadHead, thread); + thread->semaphorePending = NULL; + thread->returnCode = 0; + OS_ThreadReschedule(0); + } + OS_CriticalEnd(state); +} + + + +/***************** Mutex ******************/ +/******************************************/ +//Create a mutex (a thread aware semaphore) +OS_Mutex_t *OS_MutexCreate(const char *name) +{ + OS_Mutex_t *mutex; + + mutex = (OS_Mutex_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Mutex_t)); + if(mutex == NULL) + return NULL; + mutex->semaphore = OS_SemaphoreCreate(name, 1); + if(mutex->semaphore == NULL) + return NULL; + mutex->thread = NULL; + mutex->count = 0; + return mutex; +} + + +/******************************************/ +void OS_MutexDelete(OS_Mutex_t *mutex) +{ + OS_SemaphoreDelete(mutex->semaphore); + OS_HeapFree(mutex); +} + + +/******************************************/ +void OS_MutexPend(OS_Mutex_t *mutex) +{ + OS_Thread_t *thread; + + assert(mutex); + thread = OS_ThreadSelf(); + if(thread == mutex->thread) + { + ++mutex->count; + return; + } + OS_SemaphorePend(mutex->semaphore, OS_WAIT_FOREVER); + mutex->thread = thread; + mutex->count = 1; +} + + +/******************************************/ +void OS_MutexPost(OS_Mutex_t *mutex) +{ + assert(mutex); + assert(mutex->thread == OS_ThreadSelf()); + assert(mutex->count > 0); + if(--mutex->count <= 0) + { + mutex->thread = NULL; + OS_SemaphorePost(mutex->semaphore); + } +} + + + +/***************** MQueue *****************/ +/******************************************/ +//Create a message queue +OS_MQueue_t *OS_MQueueCreate(const char *name, + int messageCount, + int messageBytes) +{ + OS_MQueue_t *queue; + int size; + + assert((messageBytes & 3) == 0); + size = messageBytes / sizeof(uint32); + queue = (OS_MQueue_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_MQueue_t) + + messageCount * size * 4); + if(queue == NULL) + return queue; + queue->name = name; + queue->semaphore = OS_SemaphoreCreate(name, 0); + if(queue->semaphore == NULL) + return NULL; + queue->count = messageCount; + queue->size = size; + queue->used = 0; + queue->read = 0; + queue->write = 0; + return queue; +} + + +/******************************************/ +void OS_MQueueDelete(OS_MQueue_t *mQueue) +{ + OS_SemaphoreDelete(mQueue->semaphore); + OS_HeapFree(mQueue); +} + + +/******************************************/ +//Send a message that is messageBytes long (defined during create) +int OS_MQueueSend(OS_MQueue_t *mQueue, void *message) +{ + uint32 state, *dst, *src; + int i; + + assert(mQueue); + src = (uint32*)message; + state = OS_CriticalBegin(); //Disable interrupts + if(++mQueue->used > mQueue->count) + { + //The message queue is full so discard the message + --mQueue->used; + OS_CriticalEnd(state); + return -1; + } + dst = (uint32*)(mQueue + 1) + mQueue->write * mQueue->size; + for(i = 0; i < mQueue->size; ++i) //Copy the message into the queue + dst[i] = src[i]; + if(++mQueue->write >= mQueue->count) + mQueue->write = 0; + OS_CriticalEnd(state); //Re-enable interrupts + OS_SemaphorePost(mQueue->semaphore); //Wakeup the receiving thread + return 0; +} + + +/******************************************/ +//Receive a message that is messageBytes long (defined during create) +//Wait at most ~10 msec ticks +int OS_MQueueGet(OS_MQueue_t *mQueue, void *message, int ticks) +{ + uint32 state, *dst, *src; + int i, rc; + + assert(mQueue); + rc = OS_SemaphorePend(mQueue->semaphore, ticks); //Wait for message + if(rc) + return rc; //Request timed out so rc = -1 + state = OS_CriticalBegin(); //Disable interrupts + --mQueue->used; + dst = (uint32*)message; + src = (uint32*)(mQueue + 1) + mQueue->read * mQueue->size; + for(i = 0; i < mQueue->size; ++i) //Copy message from the queue + dst[i] = src[i]; + if(++mQueue->read >= mQueue->count) + mQueue->read = 0; + OS_CriticalEnd(state); //Re-enable interrupts + return 0; +} + + + +/***************** Jobs *******************/ +/******************************************/ +typedef void (*JobFunc_t)(); +static OS_MQueue_t *jobQueue; +static OS_Thread_t *jobThread; + +//This thread waits for jobs that request a function to be called +static void JobThread(void *arg) +{ + uint32 message[4]; + JobFunc_t funcPtr; + (void)arg; + for(;;) + { + OS_MQueueGet(jobQueue, message, OS_WAIT_FOREVER); + funcPtr = (JobFunc_t)message[0]; + funcPtr(message[1], message[2], message[3]); + } +} + + +/******************************************/ +//Call a function using the job thread so the caller won't be blocked +void OS_Job(void (*funcPtr)(), void *arg0, void *arg1, void *arg2) +{ + uint32 message[4]; + int rc; + + OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); + if(jobThread == NULL) + { + jobQueue = OS_MQueueCreate("job", 100, 16); + jobThread = OS_ThreadCreate("job", JobThread, NULL, 150, 4000); + } + OS_SemaphorePost(SemaphoreLock); + + message[0] = (uint32)funcPtr; + message[1] = (uint32)arg0; + message[2] = (uint32)arg1; + message[3] = (uint32)arg2; + rc = OS_MQueueSend(jobQueue, message); +} + + +/***************** Timer ******************/ +/******************************************/ +//This thread polls the list of timers to see if any have timed out +static void OS_TimerThread(void *arg) +{ + uint32 timeNow; + int diff, ticks; + uint32 message[8]; + OS_Timer_t *timer; + (void)arg; + + timeNow = OS_ThreadTime(); //Number of ~10 msec ticks since reboot + for(;;) + { + //Determine how long to sleep + OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); + if(TimerHead) + ticks = TimerHead->ticksTimeout - timeNow; + else + ticks = OS_WAIT_FOREVER; + OS_SemaphorePost(SemaphoreLock); + OS_SemaphorePend(SemaphoreTimer, ticks); + + //Send messages for all timed out timers + timeNow = OS_ThreadTime(); + for(;;) + { + timer = NULL; + OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); + if(TimerHead) + { + diff = timeNow - TimerHead->ticksTimeout; + if(diff >= 0) + timer = TimerHead; + } + OS_SemaphorePost(SemaphoreLock); + if(timer == NULL) + break; + if(timer->ticksRestart) + OS_TimerStart(timer, timer->ticksRestart, timer->ticksRestart); + else + OS_TimerStop(timer); + + if(timer->callback) + timer->callback(timer, timer->info); + else + { + //Send message + message[0] = MESSAGE_TYPE_TIMER; + message[1] = (uint32)timer; + message[2] = timer->info; + OS_MQueueSend(timer->mqueue, message); + } + } + } +} + + +/******************************************/ +//Create a timer that will send a message upon timeout +OS_Timer_t *OS_TimerCreate(const char *name, OS_MQueue_t *mQueue, uint32 info) +{ + OS_Timer_t *timer; + + OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); + if(SemaphoreTimer == NULL) + { + SemaphoreTimer = OS_SemaphoreCreate("Timer", 0); + OS_ThreadCreate("Timer", OS_TimerThread, NULL, 250, 2000); + } + OS_SemaphorePost(SemaphoreLock); + + timer = (OS_Timer_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Timer_t)); + if(timer == NULL) + return NULL; + timer->name = name; + timer->callback = NULL; + timer->mqueue = mQueue; + timer->next = NULL; + timer->prev = NULL; + timer->info = info; + timer->active = 0; + return timer; +} + + +/******************************************/ +void OS_TimerDelete(OS_Timer_t *timer) +{ + OS_TimerStop(timer); + OS_HeapFree(timer); +} + + +/******************************************/ +void OS_TimerCallback(OS_Timer_t *timer, OS_TimerFuncPtr_t callback) +{ + timer->callback = callback; +} + + +/******************************************/ +//Must not be called from an ISR +//In ~10 msec ticks send a message (or callback) +void OS_TimerStart(OS_Timer_t *timer, uint32 ticks, uint32 ticksRestart) +{ + OS_Timer_t *node, *prev; + int diff, check=0; + + assert(timer); + assert(InterruptInside[OS_CpuIndex()] == 0); + ticks += OS_ThreadTime(); + if(timer->active) + OS_TimerStop(timer); + OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); + if(timer->active) + { + //Prevent race condition + OS_SemaphorePost(SemaphoreLock); + return; + } + timer->ticksTimeout = ticks; + timer->ticksRestart = ticksRestart; + timer->active = 1; + prev = NULL; + for(node = TimerHead; node; node = node->next) + { + diff = ticks - node->ticksTimeout; + if(diff <= 0) + break; + prev = node; + } + timer->next = node; + timer->prev = prev; + if(node) + node->prev = timer; + if(prev == NULL) + { + TimerHead = timer; + check = 1; + } + else + prev->next = timer; + OS_SemaphorePost(SemaphoreLock); + if(check) + OS_SemaphorePost(SemaphoreTimer); //Wakeup OS_TimerThread +} + + +/******************************************/ +//Must not be called from an ISR +void OS_TimerStop(OS_Timer_t *timer) +{ + assert(timer); + assert(InterruptInside[OS_CpuIndex()] == 0); + OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); + if(timer->active) + { + timer->active = 0; + if(timer->prev == NULL) + TimerHead = timer->next; + else + timer->prev->next = timer->next; + if(timer->next) + timer->next->prev = timer->prev; + } + OS_SemaphorePost(SemaphoreLock); +} + + +/***************** ISR ********************/ +/******************************************/ +void OS_InterruptServiceRoutine(uint32 status, uint32 *stack) +{ + int i; + uint32 state, cpuIndex = OS_CpuIndex(); + + if(status == 0 && Isr[31]) + Isr[31](stack); //SYSCALL or BREAK + + InterruptInside[cpuIndex] = 1; + i = 0; + do + { + if(status & 1) + { + if(Isr[i]) + Isr[i](stack); + else + OS_InterruptMaskClear(1 << i); + } + status >>= 1; + ++i; + } while(status); + InterruptInside[cpuIndex] = 0; + + state = OS_SpinLock(); + if(ThreadNeedReschedule[cpuIndex]) + OS_ThreadReschedule(ThreadNeedReschedule[cpuIndex] & 1); + OS_SpinUnlock(state); +} + + +/******************************************/ +void OS_InterruptRegister(uint32 mask, OS_FuncPtr_t funcPtr) +{ + int i; + + for(i = 0; i < 32; ++i) + { + if(mask & (1 << i)) + Isr[i] = funcPtr; + } +} + + +/******************************************/ +//Plasma hardware dependent +uint32 OS_InterruptStatus(void) +{ + return MemoryRead(IRQ_STATUS); +} + + +/******************************************/ +//Plasma hardware dependent +uint32 OS_InterruptMaskSet(uint32 mask) +{ + uint32 state; + state = OS_CriticalBegin(); + mask |= MemoryRead(IRQ_MASK); + MemoryWrite(IRQ_MASK, mask); + OS_CriticalEnd(state); + return mask; +} + + +/******************************************/ +//Plasma hardware dependent +uint32 OS_InterruptMaskClear(uint32 mask) +{ + uint32 state; + state = OS_CriticalBegin(); + mask = MemoryRead(IRQ_MASK) & ~mask; + MemoryWrite(IRQ_MASK, mask); + OS_CriticalEnd(state); + return mask; +} + + +/**************** Init ********************/ +/******************************************/ +//If there aren't any other ready to run threads then spin here +static volatile uint32 IdleCount; +static void OS_IdleThread(void *arg) +{ + (void)arg; + + //Don't block in the idle thread! + for(;;) + { + ++IdleCount; + } +} + + +/******************************************/ +#ifndef DISABLE_IRQ_SIM +//Simulate the hardware interrupts +static void OS_IdleSimulateIsr(void *arg) +{ + uint32 count=0, value; + (void)arg; + + for(;;) + { + MemoryRead(IRQ_MASK + 4); //calls Sleep(10) +#if WIN32 + while(OS_InterruptMaskSet(0) & IRQ_UART_WRITE_AVAILABLE) + OS_InterruptServiceRoutine(IRQ_UART_WRITE_AVAILABLE, 0); +#endif + value = OS_InterruptMaskSet(0) & 0xf; + if(value) + OS_InterruptServiceRoutine(value, 0); + ++count; + } +} +#endif //DISABLE_IRQ_SIM + + +/******************************************/ +//Plasma hardware dependent +//ISR called every ~10 msecs when bit 18 of the counter register toggles +static void OS_ThreadTickToggle(void *arg) +{ + uint32 status, mask, state; + + //Toggle looking for IRQ_COUNTER18 or IRQ_COUNTER18_NOT + state = OS_SpinLock(); + status = MemoryRead(IRQ_STATUS) & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT); + mask = MemoryRead(IRQ_MASK) | IRQ_COUNTER18 | IRQ_COUNTER18_NOT; + mask &= ~status; + MemoryWrite(IRQ_MASK, mask); + OS_ThreadTick(arg); + OS_SpinUnlock(state); +} + + +/******************************************/ +//Initialize the OS by setting up the system heap and the tick interrupt +void OS_Init(uint32 *heapStorage, uint32 bytes) +{ + int i; + if((int)OS_Init > 0x10000000) //Running from DDR? + OS_AsmInterruptInit(); //Patch interrupt vector + OS_InterruptMaskClear(0xffffffff); //Disable interrupts + HeapArray[0] = OS_HeapCreate("Default", heapStorage, bytes); + HeapArray[1] = HeapArray[0]; + SemaphoreSleep = OS_SemaphoreCreate("Sleep", 0); + SemaphoreRelease = OS_SemaphoreCreate("Release", 1); + SemaphoreLock = OS_SemaphoreCreate("Lock", 1); + for(i = 0; i < OS_CPU_COUNT; ++i) + OS_ThreadCreate("Idle", OS_IdleThread, NULL, 0, 256); +#ifndef DISABLE_IRQ_SIM + if((OS_InterruptStatus() & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT)) == 0) + { + //Detected that running in simulator so create SimIsr thread + UartPrintfCritical("SimIsr\n"); + OS_ThreadCreate("SimIsr", OS_IdleSimulateIsr, NULL, 1, 0); + } +#endif //DISABLE_IRQ_SIM + //Plasma hardware dependent (register for OS tick interrupt every ~10 msecs) + OS_InterruptRegister(IRQ_COUNTER18 | IRQ_COUNTER18_NOT, OS_ThreadTickToggle); + OS_InterruptMaskSet(IRQ_COUNTER18 | IRQ_COUNTER18_NOT); +} + + +/******************************************/ +//Start thread swapping +void OS_Start(void) +{ + ThreadSwapEnabled = 1; + (void)OS_SpinLock(); + OS_ThreadReschedule(1); +} + + +/******************************************/ +//Place breakpoint here +void OS_Assert(void) +{ +} + + +#if OS_CPU_COUNT > 1 +static uint8 SpinLockArray[OS_CPU_COUNT]; +/******************************************/ +uint32 OS_CpuIndex(void) +{ + return 0; //0 to OS_CPU_COUNT-1 +} + + +/******************************************/ +//Symmetric Multiprocessing Spin Lock Mutex +uint32 OS_SpinLock(void) +{ + uint32 state, cpuIndex, i, j, ok, delay; + + cpuIndex = OS_CpuIndex(); + delay = cpuIndex + 8; + state = OS_AsmInterruptEnable(0); + //Spin until only this CPU has the spin lock + do + { + ok = 1; + if(++SpinLockArray[cpuIndex] == 1) + { + for(i = 0; i < OS_CPU_COUNT; ++i) + { + if(i != cpuIndex && SpinLockArray[i]) + ok = 0; //Another CPU has the spin lock + } + if(ok == 0) + { + SpinLockArray[cpuIndex] = 0; + for(j = 0; j < delay; ++j) //wait a bit + ++i; + if(delay < 128) + delay <<= 1; + } + } + } while(ok == 0); + return state; +} + + +/******************************************/ +void OS_SpinUnlock(uint32 state) +{ + uint32 cpuIndex; + cpuIndex = OS_CpuIndex(); + if(--SpinLockArray[cpuIndex] == 0) + OS_AsmInterruptEnable(state); + + assert(SpinLockArray[cpuIndex] < 10); +} +#endif //OS_CPU_COUNT > 1 + + +/************** WIN32/Linux Support *************/ +#ifdef WIN32 +#ifdef LINUX +#define putch putchar +#undef _LIBC +#undef kbhit +#undef getch +#define UartPrintf UartPrintf2 +#define UartScanf UartScanf2 +#include +#include +#include +#include +//Support RTOS inside Linux +void Sleep(unsigned int value) +{ + usleep(value * 1000); +} + +int kbhit(void) +{ + struct termios oldt, newt; + struct timeval tv; + fd_set read_fd; + + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + tv.tv_sec=0; + tv.tv_usec=0; + FD_ZERO(&read_fd); + FD_SET(0,&read_fd); + if(select(1, &read_fd, NULL, NULL, &tv) == -1) + return 0; + if(FD_ISSET(0,&read_fd)) + return 1; + return 0; +} + +int getch(void) +{ + struct termios oldt, newt; + int ch; + + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + ch = getchar(); + return ch; +} +#else +//Support RTOS inside Windows +#undef kbhit +#undef getch +#undef putch +extern int kbhit(); +extern int getch(void); +extern int putch(int); +extern void __stdcall Sleep(unsigned long value); +#endif + +static uint32 Memory[8]; + +//Simulates device register memory reads +uint32 MemoryRead(uint32 address) +{ + Memory[2] |= IRQ_UART_WRITE_AVAILABLE; //IRQ_STATUS + switch(address) + { + case UART_READ: + if(kbhit()) + Memory[0] = getch(); //UART_READ + Memory[2] &= ~IRQ_UART_READ_AVAILABLE; //clear bit + return Memory[0]; + case IRQ_MASK: + return Memory[1]; //IRQ_MASK + case IRQ_MASK + 4: + Sleep(10); + return 0; + case IRQ_STATUS: + if(kbhit()) + Memory[2] |= IRQ_UART_READ_AVAILABLE; + return Memory[2]; + } + return 0; +} + +//Simulates device register memory writes +void MemoryWrite(uint32 address, uint32 value) +{ + switch(address) + { + case UART_WRITE: + putch(value); + break; + case IRQ_MASK: + Memory[1] = value; + break; + case IRQ_STATUS: + Memory[2] = value; + break; + } +} + +uint32 OS_AsmInterruptEnable(uint32 enableInterrupt) +{ + return enableInterrupt; +} + +void OS_AsmInterruptInit(void) +{ +} +#endif //WIN32 + + +/**************** Example *****************/ +#ifndef NO_MAIN +#ifdef WIN32 +static uint8 HeapSpace[1024*512]; //For simulation on a PC +#endif + +int main(int programEnd, char *argv[]) +{ + (void)programEnd; //Pointer to end of used memory + (void)argv; + + UartPrintfCritical("Starting RTOS\n"); +#ifdef WIN32 + OS_Init((uint32*)HeapSpace, sizeof(HeapSpace)); //For PC simulation +#else + //Create heap in remaining space after program in 1MB external RAM + OS_Init((uint32*)programEnd, + RAM_EXTERNAL_BASE + RAM_EXTERNAL_SIZE - programEnd); +#endif + UartInit(); + OS_ThreadCreate("Main", MainThread, NULL, 100, 4000); + OS_Start(); + return 0; +} +#endif //NO_MAIN + diff --git a/kernel/rtos.h b/kernel/rtos.h new file mode 100644 index 0000000..5fbe66f --- /dev/null +++ b/kernel/rtos.h @@ -0,0 +1,377 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Real Time Operating System + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/17/05 + * FILENAME: rtos.h + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma Real Time Operating System + *--------------------------------------------------------------------*/ +#ifndef __RTOS_H__ +#define __RTOS_H__ + +// Symmetric Multi-Processing +#define OS_CPU_COUNT 1 + +// Typedefs +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +// Memory Access +#ifdef WIN32 + uint32 MemoryRead(uint32 Address); + void MemoryWrite(uint32 Address, uint32 Value); +#else + #define MemoryRead(A) (*(volatile uint32*)(A)) + #define MemoryWrite(A,V) *(volatile uint32*)(A)=(V) +#endif + +/***************** LibC ******************/ +#if !defined(_LIBC) && !defined(_CTYPE_DEFINED) +#define printf UartPrintf +//#define printf UartPrintfPoll +#define scanf UartScanf +#ifndef WIN32 + #define malloc(S) OS_HeapMalloc(NULL, S) + #define free(S) OS_HeapFree(S) +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + +#define assert(A) if((A)==0){OS_Assert();UartPrintfCritical("\r\nAssert %s:%d\r\n", __FILE__, __LINE__);} + +#define isprint(c) (' '<=(c)&&(c)<='~') +#define isspace(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\r') +#define isdigit(c) ('0'<=(c)&&(c)<='9') +#define islower(c) ('a'<=(c)&&(c)<='z') +#define isupper(c) ('A'<=(c)&&(c)<='Z') +#define isalpha(c) (islower(c)||isupper(c)) +#define isalnum(c) (isalpha(c)||isdigit(c)) +#undef min +#define min(a,b) ((a)<(b)?(a):(b)) +#define strcpy strcpy2 //don't use intrinsic functions +#define strcat strcat2 +#define strncat strncat2 +#define strcmp strcmp2 +#define strlen strlen2 +#define memcpy memcpy2 +#define memcmp memcmp2 +#define memset memset2 +#define abs abs2 +#define atoi atoi2 + +char *strcpy(char *dst, const char *src); +char *strncpy(char *dst, const char *src, int count); +char *strcat(char *dst, const char *src); +char *strncat(char *dst, const char *src, int count); +int strcmp(const char *string1, const char *string2); +int strncmp(const char *string1, const char *string2, int count); +char *strstr(const char *string, const char *find); +int strlen(const char *string); +void *memcpy(void *dst, const void *src, unsigned long bytes); +void *memmove(void *dst, const void *src, unsigned long bytes); +int memcmp(const void *cs, const void *ct, unsigned long bytes); +void *memset(void *dst, int c, unsigned long bytes); +int abs(int n); +int rand(void); +void srand(unsigned int seed); +long strtol(const char *s, char **end, int base); +int atoi(const char *s); +char *itoa(int num, char *dst, int base); +#ifndef NO_ELLIPSIS + int sprintf(char *s, const char *format, ...); + int sscanf(const char *s, const char *format, ...); +#endif +#ifdef INCLUDE_DUMP + void dump(const unsigned char *data, int length); +#endif +#ifdef INCLUDE_QSORT + void qsort(void *base, + long n, + long size, + int (*cmp)(const void *,const void *)); + void *bsearch(const void *key, + const void *base, + long n, + long size, + int (*cmp)(const void *,const void *)); +#endif +#ifdef INCLUDE_TIMELIB + #define difftime(time2,time1) (time2-time1) + typedef unsigned long time_t; //start at 1/1/80 + struct tm { + int tm_sec; //(0,59) + int tm_min; //(0,59) + int tm_hour; //(0,23) + int tm_mday; //(1,31) + int tm_mon; //(0,11) + int tm_year; //(0,n) from 1900 + int tm_wday; //(0,6) calculated + int tm_yday; //(0,365) calculated + int tm_isdst; // calculated + }; + time_t mktime(struct tm *tp); + void gmtime_r(const time_t *tp, struct tm *out); + void gmtimeDst(time_t dstTimeIn, time_t dstTimeOut); + void gmtimeDstSet(time_t *tp, time_t *dstTimeIn, time_t *dstTimeOut); +#endif +#define _LIBC +#endif //_LIBC + +/***************** Assembly **************/ +typedef uint32 jmp_buf[20]; +extern uint32 OS_AsmInterruptEnable(uint32 state); +extern void OS_AsmInterruptInit(void); +extern int setjmp(jmp_buf env); +extern void longjmp(jmp_buf env, int val); +extern uint32 OS_AsmMult(uint32 a, uint32 b, unsigned long *hi); +extern void *OS_Syscall(); + +/***************** Heap ******************/ +#define HEAP_USER (void*)0 +#define HEAP_SYSTEM (void*)1 +#define HEAP_SMALL (void*)2 +#define HEAP_UI (void*)3 +typedef struct OS_Heap_s OS_Heap_t; +OS_Heap_t *OS_HeapCreate(const char *name, void *memory, uint32 size); +void OS_HeapDestroy(OS_Heap_t *heap); +void *OS_HeapMalloc(OS_Heap_t *heap, int bytes); +void OS_HeapFree(void *block); +void OS_HeapAlternate(OS_Heap_t *heap, OS_Heap_t *alternate); +void OS_HeapRegister(void *index, OS_Heap_t *heap); + +/***************** Critical Sections *****************/ +#if OS_CPU_COUNT <= 1 + // Single CPU + #define OS_CpuIndex() 0 + #define OS_CriticalBegin() OS_AsmInterruptEnable(0) + #define OS_CriticalEnd(S) OS_AsmInterruptEnable(S) + #define OS_SpinLock() 0 + #define OS_SpinUnlock(S) +#else + // Symmetric multiprocessing + uint32 OS_CpuIndex(void); + #define OS_CriticalBegin() OS_SpinLock() + #define OS_CriticalEnd(S) OS_SpinUnlock(S) + uint32 OS_SpinLock(void); + void OS_SpinUnlock(uint32 state); +#endif + +/***************** Thread *****************/ +#ifdef WIN32 + #define STACK_SIZE_MINIMUM (1024*4) +#else + #define STACK_SIZE_MINIMUM (1024*1) +#endif +#define STACK_SIZE_DEFAULT 1024*2 +#undef THREAD_PRIORITY_IDLE +#define THREAD_PRIORITY_IDLE 0 +#define THREAD_PRIORITY_MAX 255 + +typedef void (*OS_FuncPtr_t)(void *arg); +typedef struct OS_Thread_s OS_Thread_t; +OS_Thread_t *OS_ThreadCreate(const char *name, + OS_FuncPtr_t funcPtr, + void *arg, + uint32 priority, + uint32 stackSize); +void OS_ThreadExit(void); +OS_Thread_t *OS_ThreadSelf(void); +void OS_ThreadSleep(int ticks); +uint32 OS_ThreadTime(void); +void OS_ThreadInfoSet(OS_Thread_t *thread, uint32 index, void *info); +void *OS_ThreadInfoGet(OS_Thread_t *thread, uint32 index); +uint32 OS_ThreadPriorityGet(OS_Thread_t *thread); +void OS_ThreadPrioritySet(OS_Thread_t *thread, uint32 priority); +void OS_ThreadProcessId(OS_Thread_t *thread, uint32 processId, OS_Heap_t *heap); +void OS_ThreadTick(void *arg); +void OS_ThreadCpuLock(OS_Thread_t *thread, int cpuIndex); + +/***************** Semaphore **************/ +#define OS_SUCCESS 0 +#define OS_ERROR -1 +#define OS_WAIT_FOREVER -1 +#define OS_NO_WAIT 0 +typedef struct OS_Semaphore_s OS_Semaphore_t; +OS_Semaphore_t *OS_SemaphoreCreate(const char *name, uint32 count); +void OS_SemaphoreDelete(OS_Semaphore_t *semaphore); +int OS_SemaphorePend(OS_Semaphore_t *semaphore, int ticks); //tick ~= 10ms +void OS_SemaphorePost(OS_Semaphore_t *semaphore); + +/***************** Mutex ******************/ +typedef struct OS_Mutex_s OS_Mutex_t; +OS_Mutex_t *OS_MutexCreate(const char *name); +void OS_MutexDelete(OS_Mutex_t *semaphore); +void OS_MutexPend(OS_Mutex_t *semaphore); +void OS_MutexPost(OS_Mutex_t *semaphore); + +/***************** MQueue *****************/ +enum { + MESSAGE_TYPE_USER = 0, + MESSAGE_TYPE_TIMER = 5 +}; +typedef struct OS_MQueue_s OS_MQueue_t; +OS_MQueue_t *OS_MQueueCreate(const char *name, + int messageCount, + int messageBytes); +void OS_MQueueDelete(OS_MQueue_t *mQueue); +int OS_MQueueSend(OS_MQueue_t *mQueue, void *message); +int OS_MQueueGet(OS_MQueue_t *mQueue, void *message, int ticks); + +/***************** Job ********************/ +void OS_Job(void (*funcPtr)(), void *arg0, void *arg1, void *arg2); + +/***************** Timer ******************/ +typedef struct OS_Timer_s OS_Timer_t; +typedef void (*OS_TimerFuncPtr_t)(OS_Timer_t *timer, uint32 info); +OS_Timer_t *OS_TimerCreate(const char *name, OS_MQueue_t *mQueue, uint32 info); +void OS_TimerDelete(OS_Timer_t *timer); +void OS_TimerCallback(OS_Timer_t *timer, OS_TimerFuncPtr_t callback); +void OS_TimerStart(OS_Timer_t *timer, uint32 ticks, uint32 ticksRestart); +void OS_TimerStop(OS_Timer_t *timer); + +/***************** ISR ********************/ +#define STACK_EPC 88/4 +void OS_InterruptServiceRoutine(uint32 status, uint32 *stack); +void OS_InterruptRegister(uint32 mask, OS_FuncPtr_t funcPtr); +uint32 OS_InterruptStatus(void); +uint32 OS_InterruptMaskSet(uint32 mask); +uint32 OS_InterruptMaskClear(uint32 mask); + +/***************** Init ******************/ +void OS_Init(uint32 *heapStorage, uint32 bytes); +void OS_Start(void); +void OS_Assert(void); +void OS_DebuggerInit(void); +void MainThread(void *Arg); + +/***************** MMU ******************/ +typedef struct { + const char *name; + OS_FuncPtr_t funcPtr; + void *arg; + uint32 priority; + uint32 stackSize; + uint32 heapSize; + uint32 processId; + OS_Semaphore_t *semaphoreDone; + uint8 *memory; //private + OS_Heap_t *heap; //private + OS_Thread_t *thread; //private +} OS_Process_t; +void OS_MMUInit(void); +void OS_MMUMemoryRegister(uint32 processId, + uint32 virtualAddress, + uint32 physicalAddress, + uint32 size, + uint32 writable); +OS_Process_t *OS_MMUProcessCreate(OS_Process_t *process); +void OS_MMUProcessDelete(OS_Process_t *process); +void OS_MMUUartPrintf(); +void OS_MMUUartScanf(); +void OS_MMUUartPrintfCritical(); + +/***************** UART ******************/ +typedef uint8* (*PacketGetFunc_t)(void); +void UartInit(void); +void UartWrite(int ch); +uint8 UartRead(void); +void UartWriteData(uint8 *data, int length); +void UartReadData(uint8 *data, int length); +#ifndef NO_ELLIPSIS2 +void UartPrintf(const char *format, ...); +void UartPrintfPoll(const char *format, ...); +void UartPrintfCritical(const char *format, ...); +void UartPrintfNull(const char *format, ...); +void UartScanf(const char *format, ...); +#endif +void UartPacketConfig(PacketGetFunc_t packetGetFunc, + int packetSize, + OS_MQueue_t *mQueue); +void UartPacketSend(uint8 *data, int bytes); +#ifdef WIN32 +#define puts puts2 +#define getch getch2 +#define kbhit kbhit2 +#endif +int puts(const char *string); +int getch(void); +int kbhit(void); +void LogWrite(int a); +void LogDump(void); +void Led(int mask, int value); + +/***************** Keyboard **************/ +#define KEYBOARD_RAW 0x100 +#define KEYBOARD_E0 0x200 +#define KEYBOARD_RELEASE 0x400 +void KeyboardInit(void); +int KeyboardGetch(void); + +/***************** Math ******************/ +//IEEE single precision floating point math +#ifndef WIN32 +#define FP_Neg __negsf2 +#define FP_Add __addsf3 +#define FP_Sub __subsf3 +#define FP_Mult __mulsf3 +#define FP_Div __divsf3 +#define FP_ToLong __fixsfsi +#define FP_ToFloat __floatsisf +#define sqrt FP_Sqrt +#define cos FP_Cos +#define sin FP_Sin +#define atan FP_Atan +#define log FP_Log +#define exp FP_Exp +#endif +float FP_Neg(float a_fp); +float FP_Add(float a_fp, float b_fp); +float FP_Sub(float a_fp, float b_fp); +float FP_Mult(float a_fp, float b_fp); +float FP_Div(float a_fp, float b_fp); +long FP_ToLong(float a_fp); +float FP_ToFloat(long af); +int FP_Cmp(float a_fp, float b_fp); +float FP_Sqrt(float a); +float FP_Cos(float rad); +float FP_Sin(float rad); +float FP_Atan(float x); +float FP_Atan2(float y, float x); +float FP_Exp(float x); +float FP_Log(float x); +float FP_Pow(float x, float y); + +/***************** Filesys ******************/ +#ifdef INCLUDE_FILESYS +#define FILE OS_FILE +#define fopen OS_fopen +#define fclose OS_fclose +#define fread OS_fread +#define fwrite OS_fwrite +#define fseek OS_fseek +#endif +#define _FILESYS_ +typedef struct OS_FILE_s OS_FILE; +OS_FILE *OS_fopen(char *name, char *mode); +void OS_fclose(OS_FILE *file); +int OS_fread(void *buffer, int size, int count, OS_FILE *file); +int OS_fwrite(void *buffer, int size, int count, OS_FILE *file); +int OS_fseek(OS_FILE *file, int offset, int mode); +int OS_fmkdir(char *name); +int OS_fdir(OS_FILE *dir, char name[64]); +void OS_fdelete(char *name); +int OS_flength(char *entry); + +/***************** Flash ******************/ +void FlashRead(uint16 *dst, uint32 byteOffset, int bytes); +void FlashWrite(uint16 *src, uint32 byteOffset, int bytes); +void FlashErase(uint32 byteOffset); + +#endif //__RTOS_H__ + diff --git a/kernel/rtos_test.c b/kernel/rtos_test.c new file mode 100644 index 0000000..46f50d0 --- /dev/null +++ b/kernel/rtos_test.c @@ -0,0 +1,522 @@ +/*-------------------------------------------------------------------- + * TITLE: Test Plasma Real Time Operating System + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 1/1/06 + * FILENAME: rtos_test.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Test Plasma Real Time Operating System + *--------------------------------------------------------------------*/ +#include "plasma.h" +#include "rtos.h" +#include "tcpip.h" + +/* Including mmu.h will cause all OS calls to use SYSCALL */ +//#include "mmu.h" + +//#define DLL_SETUP +//#define DLL_CALL +//#include "dll.h" + +#define SEMAPHORE_COUNT 50 +#define TIMER_COUNT 10 + +extern void TestMathFull(void); + +typedef struct { + OS_Thread_t *MyThread[TIMER_COUNT]; + OS_Semaphore_t *MySemaphore[SEMAPHORE_COUNT]; + OS_Mutex_t *MyMutex; + OS_Timer_t *MyTimer[TIMER_COUNT]; + OS_MQueue_t *MyQueue[TIMER_COUNT]; + int TimerDone; +} TestInfo_t; + +int Global; + +//****************************************************************** +static void TestCLib(void) +{ + char s1[80], s2[80], *ptr; + int rc, v1, v2, v3; + + printf("TestCLib\n"); + strcpy(s1, "Hello "); + memset(s2, 0, sizeof(s2)); + strncpy(s2, "World wide", 5); + strcat(s1, s2); + strncat(s1, "!\nthing", 14); + printf("%s", s1); + rc = strcmp(s1, "Hello World!\n"); + assert(rc == 0); + rc = strcmp(s1, "Hello WOrld!\n"); + assert(rc > 0); + rc = strcmp(s1, "Hello world!\n"); + assert(rc < 0); + rc = strncmp(s1, "Hellx", 4); + assert(rc == 0); + ptr = strstr(s1, "orl"); + assert(ptr[0] = 'o'); + rc = strlen(s1); + assert(rc == 13); + memcpy(s2, s1, rc+1); + rc = memcmp(s1, s2, 8); + assert(rc == 0); + s2[5] = 'z'; + rc = memcmp(s1, s2, 8); + assert(rc != 0); + memset(s2, 0, 5); + memset(s2, 'a', 3); + rc = abs(-5); + itoa(1234, s1, 10); + itoa(0, s1, 10); + itoa(-1234, s1, 10); + itoa(0xabcd, s1, 16); + itoa(0x12ab, s1, 16); + sprintf(s1, "test c%c d%d 0x%x s%s End\n", 'C', 1234, 0xabcd, "String"); + printf("%s", s1); + sprintf(s1, "test c%c d%6d 0x%6x s%8s End\n", 'C', 1234, 0xabcd, "String"); + printf("%s", s1); + sscanf("1234 -1234 0xabcd text h", "%d %d %x %s", &v1, &v2, &v3, s1); + assert(v1 == 1234 && v2 == -1234 && v3 == 0xabcd); + assert(strcmp(s1, "text") == 0); + //UartScanf("%d %d", &v1, &v2); + //printf("v1 = %d v2 = %d\n", v1, v2); + printf("Done.\n"); +} + +//****************************************************************** +static void TestHeap(void) +{ + uint8 *ptrs[256], size[256], *ptr; + int i, j, k, value; + + printf("TestHeap\n"); + memset(ptrs, 0, sizeof(ptrs)); + for(i = 0; i < 1000; ++i) + { + j = rand() & 255; + if(ptrs[j]) + { + ptr = ptrs[j]; + value = size[j]; + for(k = 0; k < value; ++k) + { + if(ptr[k] != value) + printf("Error\n"); + } + OS_HeapFree(ptrs[j]); + } + size[j] = (uint8)(rand() & 255); + ptrs[j] = OS_HeapMalloc(NULL, size[j]); + if(ptrs[j] == NULL) + printf("malloc NULL\n"); + else + memset(ptrs[j], size[j], size[j]); + } + for(i = 0; i < 256; ++i) + { + if(ptrs[i]) + OS_HeapFree(ptrs[i]); + } + printf("Done.\n"); +} + +//****************************************************************** +static void MyThreadMain(void *arg) +{ + OS_Thread_t *thread; + int priority; + + thread = OS_ThreadSelf(); + priority = OS_ThreadPriorityGet(thread); + OS_ThreadSleep(10); + printf("Arg=%d thread=0x%x info=0x%x priority=%d\n", + (uint32)arg, thread, OS_ThreadInfoGet(thread, 0), priority); + OS_ThreadExit(); +} + +static void TestThread(void) +{ + OS_Thread_t *thread; + int i, priority; + + printf("TestThread\n"); + for(i = 0; i < 32; ++i) + { + priority = 50 + i; + thread = OS_ThreadCreate("MyThread", MyThreadMain, (uint32*)i, priority, 0); + OS_ThreadInfoSet(thread, 0, (void*)(0xabcd + i)); + //printf("Created thread 0x%x\n", thread); + } + + thread = OS_ThreadSelf(); + priority = OS_ThreadPriorityGet(thread); + printf("Priority = %d\n", priority); + OS_ThreadPrioritySet(thread, 200); + printf("Priority = %d\n", OS_ThreadPriorityGet(thread)); + OS_ThreadPrioritySet(thread, priority); + + printf("Thread time = %d\n", OS_ThreadTime()); + OS_ThreadSleep(100); + printf("Thread time = %d\n", OS_ThreadTime()); +} + +//****************************************************************** +static void TestSemThread(void *arg) +{ + int i; + TestInfo_t *info = (TestInfo_t*)arg; + + for(i = 0; i < SEMAPHORE_COUNT/2; ++i) + { + printf("s"); + OS_SemaphorePend(info->MySemaphore[i], OS_WAIT_FOREVER); + OS_SemaphorePost(info->MySemaphore[i + SEMAPHORE_COUNT/2]); + } + OS_ThreadExit(); +} + +static void TestSemaphore(void) +{ + int i, rc; + TestInfo_t info; + printf("TestSemaphore\n"); + for(i = 0; i < SEMAPHORE_COUNT; ++i) + { + info.MySemaphore[i] = OS_SemaphoreCreate("MySem", 0); + //printf("sem[%d]=0x%x\n", i, MySemaphore[i]); + } + + OS_ThreadCreate("TestSem", TestSemThread, &info, 50, 0); + + for(i = 0; i < SEMAPHORE_COUNT/2; ++i) + { + printf("S"); + OS_SemaphorePost(info.MySemaphore[i]); + rc = OS_SemaphorePend(info.MySemaphore[i + SEMAPHORE_COUNT/2], 500); + assert(rc == 0); + } + + printf(":"); + rc = OS_SemaphorePend(info.MySemaphore[0], 10); + assert(rc != 0); + printf(":"); + OS_SemaphorePend(info.MySemaphore[0], 100); + printf(":"); + + for(i = 0; i < SEMAPHORE_COUNT; ++i) + OS_SemaphoreDelete(info.MySemaphore[i]); + + printf("\nDone.\n"); +} + +//****************************************************************** +static void TestMutexThread(void *arg) +{ + TestInfo_t *info = (TestInfo_t*)arg; + + printf("Waiting for mutex\n"); + OS_MutexPend(info->MyMutex); + printf("Have Mutex1\n"); + OS_MutexPend(info->MyMutex); + printf("Have Mutex2\n"); + OS_MutexPend(info->MyMutex); + printf("Have Mutex3\n"); + + OS_ThreadSleep(100); + + OS_MutexPost(info->MyMutex); + OS_MutexPost(info->MyMutex); + OS_MutexPost(info->MyMutex); + + OS_ThreadExit(); +} + +static void TestMutex(void) +{ + TestInfo_t info; + printf("TestMutex\n"); + info.MyMutex = OS_MutexCreate("MyMutex"); + OS_MutexPend(info.MyMutex); + OS_MutexPend(info.MyMutex); + OS_MutexPend(info.MyMutex); + + OS_ThreadSleep(100); + + OS_ThreadCreate("TestMutex", TestMutexThread, &info, 50, 0); + + OS_ThreadSleep(50); + OS_MutexPost(info.MyMutex); + OS_MutexPost(info.MyMutex); + OS_MutexPost(info.MyMutex); + + printf("Try get mutex\n"); + OS_MutexPend(info.MyMutex); + printf("Gotit\n"); + + OS_MutexDelete(info.MyMutex); + printf("Done.\n"); +} + +//****************************************************************** +static void TestMQueue(void) +{ + OS_MQueue_t *mqueue; + char data[16]; + int i, rc; + + printf("TestMQueue\n"); + mqueue = OS_MQueueCreate("MyMQueue", 10, 16); + strcpy(data, "Test0"); + for(i = 0; i < 16; ++i) + { + data[4] = (char)('0' + i); + OS_MQueueSend(mqueue, data); + } + for(i = 0; i < 16; ++i) + { + memset(data, 0, sizeof(data)); + rc = OS_MQueueGet(mqueue, data, 20); + if(rc == 0) + printf("message=(%s)\n", data); + else + printf("timeout\n"); + } + + OS_MQueueDelete(mqueue); + printf("Done.\n"); +} + +//****************************************************************** +static void TestTimerThread(void *arg) +{ + int index; + uint32 data[4]; + OS_Timer_t *timer; + TestInfo_t *info = (TestInfo_t*)arg; + + //printf("TestTimerThread\n"); + + OS_ThreadSleep(1); + index = (int)OS_ThreadInfoGet(OS_ThreadSelf(), 0); + //printf("index=%d\n", index); + OS_MQueueGet(info->MyQueue[index], data, 1000); + timer = (OS_Timer_t*)data[1]; + printf("%d ", data[2]); + OS_MQueueGet(info->MyQueue[index], data, 1000); + printf("%d ", data[2]); + ++info->TimerDone; + OS_ThreadExit(); +} + +static void TestTimer(void) +{ + int i; + TestInfo_t info; + + printf("TestTimer\n"); + info.TimerDone = 0; + for(i = 0; i < TIMER_COUNT; ++i) + { + info.MyQueue[i] = OS_MQueueCreate("MyQueue", 10, 16); + info.MyTimer[i] = OS_TimerCreate("MyTimer", info.MyQueue[i], i); + info.MyThread[i] = OS_ThreadCreate("TimerTest", TestTimerThread, &info, 50, 0); + OS_ThreadInfoSet(info.MyThread[i], 0, (void*)i); + OS_TimerStart(info.MyTimer[i], 10+i*2, 220+i); + } + + while(info.TimerDone < TIMER_COUNT) + OS_ThreadSleep(10); + + for(i = 0; i < TIMER_COUNT; ++i) + { + OS_MQueueDelete(info.MyQueue[i]); + OS_TimerDelete(info.MyTimer[i]); + } + + printf("Done.\n"); +} + +//****************************************************************** +#if 1 +void TestMath(void) +{ + int i; + float a, b, sum, diff, mult, div; + uint32 compare; + + //Check add subtract multiply and divide + for(i = -4; i < 4; ++i) + { + a = (float)(i * 10 + (float)63.2); + b = (float)(-i * 5 + (float)3.5); + sum = a + b; + diff = a - b; + mult = a * b; + div = a / b; + printf("a=%dE-3 b=%dE-3 sum=%dE-3 diff=%dE-3 mult=%dE-3 div=%dE-3\n", + (int)(a*(float)1000), (int)(b*(float)1000), + (int)(sum*(float)1000), (int)(diff*(float)1000), + (int)(mult*(float)1000), (int)(div*(float)1000)); + } + + //Comparisons + b = (float)2.0; + compare = 0; + for(i = 1; i < 4; ++i) + { + a = (float)i; + compare = (compare << 1) | (a == b); + compare = (compare << 1) | (a != b); + compare = (compare << 1) | (a < b); + compare = (compare << 1) | (a <= b); + compare = (compare << 1) | (a > b); + compare = (compare << 1) | (a >= b); + } + printf("Compare = %8x %s\n", compare, + compare==0x1c953 ? "OK" : "ERROR"); + + //Cosine + for(a = (float)0.0; a <= (float)(3.1415); a += (float)(3.1415/16.0)) + { + b = FP_Cos(a); + printf("cos(%4dE-3) = %4dE-3\n", + (int)(a*(float)1000.0), (int)(b*(float)1000.0)); + } +} +#endif + +//****************************************************************** +#ifndef WIN32 +static void MySyscall(void *arg) +{ + uint32 *stack = arg; + stack[STACK_EPC] += 4; //skip over SYSCALL + printf("Inside MySyscall %d\n", stack[28/4]); +} + +void TestSyscall(void) +{ + OS_InterruptRegister((uint32)(1<<31), MySyscall); + OS_Syscall(57); + OS_ThreadSleep(1); + printf("Done\n"); +} +#endif + +#ifdef __MMU_ENUM_H__ +void TestProcess(void) +{ + OS_Process_t *process; + process = (OS_Process_t*)OS_HeapMalloc(NULL, sizeof(OS_Process_t)); + process->name = "test"; + process->funcPtr = MainThread; + process->arg = NULL; + process->priority = 200; + process->stackSize = 1024*32; + process->heapSize = 1024*128; + process->processId = 1; + process->semaphoreDone = OS_SemaphoreCreate("processDone", 0); + printf("Creating process\n"); + OS_MMUProcessCreate(process); + OS_SemaphorePend(process->semaphoreDone, OS_WAIT_FOREVER); + printf("Process done\n"); + OS_MMUProcessDelete(process); +} +#endif + + +//****************************************************************** +void MMUTest(void); +void HtmlThread(void *arg); +void ConsoleInit(void); +void exit(int); +uint8 macAddress[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4}; + + +void MainThread(void *Arg) +{ + int ch, i, display=1; + (void)Arg; +#ifdef __MMU_ENUM_H__ + OS_MMUInit(); +#endif + +#ifdef INCLUDE_ETH + EthernetInit(macAddress); + IPInit(EthernetTransmit, macAddress, "plasma"); + HtmlInit(1); +#endif + +#ifdef INCLUDE_HTML + IPInit(NULL, macAddress, "plasma"); + HtmlInit(1); +#endif + +#ifdef INCLUDE_CONSOLE + ConsoleInit(); +#endif + + for(;;) + { + if(display) + { + printf("\n"); + printf("1 CLib\n"); + printf("2 Heap\n"); + printf("3 Thread\n"); + printf("4 Semaphore\n"); + printf("5 Mutex\n"); + printf("6 MQueue\n"); + printf("7 Timer\n"); + printf("8 Math\n"); + printf("9 Syscall\n"); +#ifdef __MMU_ENUM_H__ + printf("p MMU Process\n"); +#endif + } + printf("> "); + display = 1; + ch = UartRead(); + printf("%c\n", ch); + switch(ch) + { +#ifdef WIN32 + case '0': exit(0); +#endif + case '1': TestCLib(); break; + case '2': TestHeap(); break; + case '3': TestThread(); break; + case '4': TestSemaphore(); break; + case '5': TestMutex(); break; + case '6': TestMQueue(); break; + case '7': TestTimer(); break; + case '8': TestMath(); break; +#ifndef WIN32 + case '9': TestSyscall(); break; +#endif +#ifdef __MMU_ENUM_H__ + case 'p': TestProcess(); break; +#endif +#ifdef WIN32 + case 'm': TestMathFull(); break; +#endif + case 'g': printf("Global=%d\n", ++Global); break; + default: + printf("E"); + display = 0; + for(i = 0; i < 30; ++i) + { + while(kbhit()) + ch = UartRead(); + OS_ThreadSleep(1); + } + break; + } + } +} + + diff --git a/kernel/tcpip.c b/kernel/tcpip.c new file mode 100644 index 0000000..b5e4c63 --- /dev/null +++ b/kernel/tcpip.c @@ -0,0 +1,1737 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma TCP/IP Protocol Stack + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 4/22/06 + * FILENAME: tcpip.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma TCP/IP Protocol Stack + * + * Possible call stack when receiving a packet: + * IPMainThread() + * IPProcessEthernetPacket() + * IPProcessTCPPacket() + * TCPSendPacket() + * IPSendPacket() + * IPChecksum() + * IPSendFrame() + * FrameInsert() + *--------------------------------------------------------------------*/ +#ifdef WIN32 +#include +#include +#include +#include +#define _LIBC +#endif +#include "rtos.h" +#define IPPRINTF +#include "tcpip.h" + + +//ETHER FIELD OFFSET LENGTH VALUE +#define ETHERNET_DEST 0 //6 +#define ETHERNET_SOURCE 6 //6 +#define ETHERNET_FRAME_TYPE 12 //2 IP=0x0800; ARP=0x0806 + +//ARP FIELD OFFSET LENGTH VALUE +#define ARP_HARD_TYPE 14 //2 0x0001 +#define ARP_PROT_TYPE 16 //2 0x0800 +#define ARP_HARD_SIZE 18 //1 0x06 +#define ARP_PROT_SIZE 19 //1 0x04 +#define ARP_OP 20 //2 ARP=1;ARPreply=2 +#define ARP_ETHERNET_SENDER 22 //6 +#define ARP_IP_SENDER 28 //4 +#define ARP_ETHERNET_TARGET 32 //6 +#define ARP_IP_TARGET 38 //4 +#define ARP_PAD 42 //18 0 + +//IP FIELD OFFSET LENGTH VALUE +#define IP_VERSION_LENGTH 14 //1 0x45 +#define IP_TYPE_OF_SERVICE 15 //1 0x00 +#define IP_LENGTH 16 //2 +#define IP_ID16 18 //2 +#define IP_FRAG_OFFSET 20 //2 +#define IP_TIME_TO_LIVE 22 //1 0x80 +#define IP_PROTOCOL 23 //1 TCP=0x06;PING=0x01;UDP=0x11 +#define IP_CHECKSUM 24 //2 +#define IP_SOURCE 26 //4 +#define IP_DEST 30 //4 + +//PSEUDO FIELD OFFSET LENGTH VALUE +#define PSEUDO_IP_SOURCE 0 //4 +#define PSEUDO_IP_DEST 4 //4 +#define PSEUDO_ZERO 8 //1 0 +#define PSEUDO_IP_PROTOCOL 9 //1 +#define PSEUDO_LENGTH 10 //2 + +//UDP FIELD OFFSET LENGTH VALUE +#define UDP_SOURCE_PORT 34 //2 +#define UDP_DEST_PORT 36 //2 +#define UDP_LENGTH 38 //2 +#define UDP_CHECKSUM 40 //2 +#define UDP_DATA 42 + +//DHCP FIELD OFFSET LENGTH VALUE +#define DHCP_OPCODE 42 //1 REQUEST=1;REPLY=2 +#define DHCP_HW_TYPE 43 //1 1 +#define DHCP_HW_LEN 44 //1 6 +#define DHCP_HOP_COUNT 45 //1 0 +#define DHCP_TRANS_ID 46 //4 +#define DHCP_NUM_SEC 50 //2 0 +#define DHCP_UNUSED 52 //2 +#define DHCP_CLIENT_IP 54 //4 +#define DHCP_YOUR_IP 58 //4 +#define DHCP_SERVER_IP 62 //4 +#define DHCP_GATEWAY_IP 66 //4 +#define DHCP_CLIENT_ETHERNET 70 //16 +#define DHCP_SERVER_NAME 86 //64 +#define DHCP_BOOT_FILENAME 150 //128 +#define DHCP_MAGIC_COOKIE 278 //4 0x63825363 +#define DHCP_OPTIONS 282 //N + +#define DHCP_MESSAGE_TYPE 53 //1 type +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_ACK 5 +#define DHCP_REQUEST_IP 50 //4 ip +#define DHCP_REQUEST_SERV_IP 54 //4 ip +#define DHCP_CLIENT_ID 61 //7 1 ethernet +#define DHCP_HOST_NAME 12 //6 plasma +#define DHCP_PARAMS 55 //4 1=subnet; 15=domain_name; 3=router; 6=dns +#define DHCP_PARAM_SUBNET 1 +#define DHCP_PARAM_ROUTER 3 +#define DHCP_PARAM_DNS 6 +#define DHCP_END_OPTION 0xff + +//DHCP FIELD OFFSET LENGTH VALUE +#define DNS_ID 0 //2 +#define DNS_FLAGS 2 //2 +#define DNS_NUM_QUESTIONS 4 //2 1 +#define DNS_NUM_ANSWERS_RR 6 //2 0/1 +#define DNS_NUM_AUTHORITY_RR 8 //2 0 +#define DNS_NUM_ADDITIONAL_RR 10 //2 0 +#define DNS_QUESTIONS 12 //2 + +#define DNS_FLAGS_RESPONSE 0x8000 +#define DNS_FLAGS_RECURSIVE 0x0100 +#define DNS_FLAGS_ERROR 0x0003 +#define DNS_FLAGS_OK 0x0000 +#define DNS_QUERY_TYPE_IP 1 +#define DNS_QUERY_CLASS 1 +#define DNS_PORT 53 + +//TCP FIELD OFFSET LENGTH VALUE +#define TCP_SOURCE_PORT 34 //2 +#define TCP_DEST_PORT 36 //2 +#define TCP_SEQ 38 //4 +#define TCP_ACK 42 //4 +#define TCP_HEADER_LENGTH 46 //1 0x50 +#define TCP_FLAGS 47 //1 SYNC=0x2;ACK=0x10;FIN=0x1 +#define TCP_WINDOW_SIZE 48 //2 +#define TCP_CHECKSUM 50 //2 +#define TCP_URGENT_POINTER 52 //2 +#define TCP_DATA 54 //length-N + +#define TCP_FLAGS_FIN 1 +#define TCP_FLAGS_SYN 2 +#define TCP_FLAGS_RST 4 +#define TCP_FLAGS_PSH 8 +#define TCP_FLAGS_ACK 16 + +//PING FIELD OFFSET LENGTH VALUE +#define PING_TYPE 34 //1 SEND=8;REPLY=0 +#define PING_CODE 35 //1 0 +#define PING_CHECKSUM 36 //2 +#define PING_ID 38 //2 +#define PING_SEQUENCE 40 //2 +#define PING_DATA 44 + +static void IPClose2(IPSocket *Socket); +static void IPArp(unsigned char ipAddress[4]); + +typedef struct ArpCache_s { + unsigned char ip[4]; + unsigned char mac[6]; +} ArpCache_t; +static ArpCache_t ArpCache[10]; +static int ArpCacheIndex; + +static uint8 ethernetAddressGateway[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +#ifndef WIN32 +static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4}; +#else +static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd5}; +#endif + +static uint8 ipAddressPlasma[] = {192, 168, 100, 10}; //changed by DHCP +static uint8 ipAddressGateway[] = {0x00, 0x00, 0x00, 0x00}; //changed by DHCP +static uint32 ipAddressDns; //changed by DHCP + +static OS_Mutex_t *IPMutex; +static int FrameFreeCount; +static IPFrame *FrameFreeHead; +static IPFrame *FrameSendHead; +static IPFrame *FrameSendTail; +static IPFrame *FrameResendHead; +static IPFrame *FrameResendTail; +static IPSocket *SocketHead; +static uint32 Seconds; +static int DhcpRetrySeconds; +static IPFuncPtr FrameSendFunc; +static OS_MQueue_t *IPMQueue; +static OS_Thread_t *IPThread; +int IPVerbose=1; + +static const unsigned char dhcpDiscover[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dest + 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //src + 0x08, 0x00, + 0x45, 0x00, 0x01, 0x48, 0x2e, 0xf5, 0x00, 0x00, //ip + 0x80, 0x11, 0x0a, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, + 0x00, 0x44, 0x00, 0x43, 0x01, 0x34, 0x45, 0x66, //udp + 0x01, 0x01, 0x06, 0x00, 0x69, 0x26, 0xb5, 0x52 //dhcp +}; + +static unsigned char dhcpOptions[] = { + 0x63, 0x82, 0x53, 0x63, //cookie + 0x35, 0x01, 0x01, //DHCP Discover + 0x3d, 0x07, 0x01, 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //Client identifier +#ifndef WIN32 + 0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'a', //Host name +#else + 0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'b', //Host name +#endif + 0x37, 0x03, DHCP_PARAM_SUBNET, DHCP_PARAM_ROUTER, DHCP_PARAM_DNS, //Parameters + DHCP_END_OPTION +}; + + +//Get a free frame; can be called from an ISR +IPFrame *IPFrameGet(int freeCount) +{ + IPFrame *frame=NULL; + uint32 state; + + state = OS_CriticalBegin(); + if(FrameFreeCount > freeCount) + { + frame = FrameFreeHead; + if(FrameFreeHead) + { + FrameFreeHead = FrameFreeHead->next; + --FrameFreeCount; + } + } + OS_CriticalEnd(state); + if(frame) + { + assert(frame->state == 0); + frame->state = 1; + } + return frame; +} + + +static void FrameFree(IPFrame *frame) +{ + uint32 state; + + assert(frame->state == 1); + frame->state = 0; + state = OS_CriticalBegin(); + frame->next = FrameFreeHead; + FrameFreeHead = frame; + ++FrameFreeCount; + OS_CriticalEnd(state); +} + + +static void FrameInsert(IPFrame **head, IPFrame **tail, IPFrame *frame) +{ + assert(frame->state == 1); + frame->state = 2; + OS_MutexPend(IPMutex); + frame->prev = NULL; + frame->next = *head; + if(*head) + (*head)->prev = frame; + *head = frame; + if(*tail == NULL) + *tail = frame; + OS_MutexPost(IPMutex); +} + + +static void FrameRemove(IPFrame **head, IPFrame **tail, IPFrame *frame) +{ + assert(frame->state == 2); + if(frame->state != 2) + { + printf("frame->state=%d\n", frame->state); + return; + } + frame->state = 1; + if(frame->prev) + frame->prev->next = frame->next; + else + *head = frame->next; + if(frame->next) + frame->next->prev = frame->prev; + else + *tail = frame->prev; + frame->prev = NULL; + frame->next = NULL; +} + + +static int IPChecksum(int checksum, const unsigned char *data, int length) +{ + int i; + checksum = ~checksum & 0xffff; + for(i = 0; i < length-1; i += 2) + { + checksum += (data[i] << 8) | data[i+1]; + } + if(i < length) + checksum += data[i] << 8; + while(checksum >> 16) + checksum = (checksum & 0xffff) + (checksum >> 16); + checksum = ~checksum & 0xffff; + return checksum; +} + + +static int EthernetVerifyChecksums(const unsigned char *packet, int length) +{ + int checksum, length2; + unsigned char pseudo[12]; + + //Calculate checksums + if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP + { + checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20); + if(checksum) + return -1; + if(packet[IP_PROTOCOL] == 0x01) //PING + { + checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE); + } + else if(packet[IP_PROTOCOL] == 0x11) //UDP + { + if(packet[UDP_CHECKSUM] == 0 && packet[UDP_CHECKSUM+1] == 0) + return 0; + memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); + memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); + pseudo[PSEUDO_ZERO] = 0; + pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; + memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2); + checksum = IPChecksum(0xffff, pseudo, 12); + length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1]; + checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length); + } + else if(packet[IP_PROTOCOL] == 0x06) //TCP + { + memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); + memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); + pseudo[PSEUDO_ZERO] = 0; + pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; + length = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1]; + length2 = length - 20; + pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8); + pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2; + checksum = IPChecksum(0xffff, pseudo, 12); + checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2); + } + if(checksum) + return -1; + } + return 0; +} + + +static void IPFrameReschedule(IPFrame *frame) +{ + int length; + length = frame->length - TCP_DATA; + if(frame->packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN)) + ++length; + if(frame->socket == NULL || frame->socket->state == IP_UDP || length == 0 || + frame->socket->state == IP_PING || ++frame->retryCnt > 4) + { + FrameFree(frame); //can't be ACK'ed + } +#ifdef WIN32 + else if(FrameFreeCount < FRAME_COUNT_SYNC) + { + FrameFree(frame); //can't be ACK'ed + } +#endif + else + { + //Put on resend list until TCP ACK'ed + frame->timeout = (short)(RETRANSMIT_TIME * frame->retryCnt); + FrameInsert(&FrameResendHead, &FrameResendTail, frame); + } +} + + +static void IPSendFrame(IPFrame *frame) +{ + uint32 message[4]; + int i; + unsigned char *packet=frame->packet; + + //Check if MAC address unknown + if(packet[ETHERNET_FRAME_TYPE+1] == 0x00 && //IP + packet[ETHERNET_DEST] == 0xff && packet[IP_DEST] != 0xff) + { + for(i = 0; i < sizeof(ArpCache) / sizeof(ArpCache_t); ++i) + { + if(memcmp(packet+IP_DEST, ArpCache[i].ip, 4) == 0) + { + memcpy(packet+ETHERNET_DEST, ArpCache[i].mac, 6); + if(frame->socket) + memcpy(frame->socket->headerSend+ETHERNET_DEST, ArpCache[i].mac, 6); + break; + } + } + if(packet[ETHERNET_DEST] == 0xff) + IPArp(packet+IP_DEST); + } + + if(FrameSendFunc) + { + //Single threaded + FrameSendFunc(frame->packet, frame->length); + IPFrameReschedule(frame); + } + else + { + //Add Packet to send queue + FrameInsert(&FrameSendHead, &FrameSendTail, frame); + + //Wakeup sender thread + message[0] = 2; + OS_MQueueSend(IPMQueue, message); + } +} + + +static void IPSendPacket(IPSocket *socket, IPFrame *frame, int length) +{ + int checksum, length2=length; + unsigned char pseudo[12], *packet=frame->packet; + + frame->length = (uint16)length; + + //Calculate checksums + if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP + { + length2 = length - IP_VERSION_LENGTH; + packet[IP_LENGTH] = (uint8)(length2 >> 8); + packet[IP_LENGTH+1] = (uint8)length2; + memset(packet+IP_CHECKSUM, 0, 2); + checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20); + packet[IP_CHECKSUM] = (unsigned char)(checksum >> 8); + packet[IP_CHECKSUM+1] = (unsigned char)checksum; + if(packet[IP_PROTOCOL] == 0x01) //ICMP & PING + { + memset(packet+PING_CHECKSUM, 0, 2); + checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE); + packet[PING_CHECKSUM] = (unsigned char)(checksum >> 8); + packet[PING_CHECKSUM+1] = (unsigned char)checksum; + } + else if(packet[IP_PROTOCOL] == 0x11) //UDP + { + length2 = length - UDP_SOURCE_PORT; + packet[UDP_LENGTH] = (uint8)(length2 >> 8); + packet[UDP_LENGTH+1] = (uint8)length2; + memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); + memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); + pseudo[PSEUDO_ZERO] = 0; + pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; + memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2); + checksum = IPChecksum(0xffff, pseudo, 12); + memset(packet+UDP_CHECKSUM, 0, 2); + length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1]; + checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length2); + packet[UDP_CHECKSUM] = (unsigned char)(checksum >> 8); + packet[UDP_CHECKSUM+1] = (unsigned char)checksum; + } + else if(packet[IP_PROTOCOL] == 0x06) //TCP + { + memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); + memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); + pseudo[PSEUDO_ZERO] = 0; + pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; + length2 = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1]; + length2 = length2 - 20; + pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8); + pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2; + checksum = IPChecksum(0xffff, pseudo, 12); + memset(packet+TCP_CHECKSUM, 0, 2); + checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2); + packet[TCP_CHECKSUM] = (unsigned char)(checksum >> 8); + packet[TCP_CHECKSUM+1] = (unsigned char)checksum; + } + } + + length2 = length - TCP_DATA; + if(socket && (packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN))) + length2 = 1; + frame->socket = socket; + frame->timeout = 0; + frame->retryCnt = 0; + if(socket) + frame->seqEnd = socket->seq + length2; + IPSendFrame(frame); +} + + +static void TCPSendPacket(IPSocket *socket, IPFrame *frame, int length) +{ + uint8 *packet = frame->packet; + int flags, count; + + flags = packet[TCP_FLAGS]; + memcpy(packet, socket->headerSend, TCP_SEQ); + packet[TCP_FLAGS] = (uint8)flags; + if(flags & TCP_FLAGS_SYN) + packet[TCP_HEADER_LENGTH] = 0x60; //set maximum segment size + else + packet[TCP_HEADER_LENGTH] = 0x50; + packet[TCP_SEQ] = (uint8)(socket->seq >> 24); + packet[TCP_SEQ+1] = (uint8)(socket->seq >> 16); + packet[TCP_SEQ+2] = (uint8)(socket->seq >> 8); + packet[TCP_SEQ+3] = (uint8)socket->seq; + packet[TCP_ACK] = (uint8)(socket->ack >> 24); + packet[TCP_ACK+1] = (uint8)(socket->ack >> 16); + packet[TCP_ACK+2] = (uint8)(socket->ack >> 8); + packet[TCP_ACK+3] = (uint8)socket->ack; + count = RECEIVE_WINDOW - (socket->ack - socket->ackProcessed); + if(count < 0) + count = 0; + packet[TCP_WINDOW_SIZE] = (uint8)(count >> 8); + packet[TCP_WINDOW_SIZE+1] = (uint8)count; + packet[TCP_URGENT_POINTER] = 0; + packet[TCP_URGENT_POINTER+1] = 0; + IPSendPacket(socket, frame, length); +} + + +static void EthernetCreateResponse(unsigned char *packetOut, + const unsigned char *packet, + int length) +{ + //Swap destination and source fields + memcpy(packetOut, packet, length); + memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6); + memcpy(packetOut+ETHERNET_SOURCE, packet+ETHERNET_DEST, 6); + if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP + { + memcpy(packetOut+IP_SOURCE, packet+IP_DEST, 4); + memcpy(packetOut+IP_DEST, packet+IP_SOURCE, 4); + if(packet[IP_PROTOCOL] == 0x06 || packet[IP_PROTOCOL] == 0x11) //TCP/UDP + { + memcpy(packetOut+TCP_SOURCE_PORT, packet+TCP_DEST_PORT, 2); + memcpy(packetOut+TCP_DEST_PORT, packet+TCP_SOURCE_PORT, 2); + } + } +} + + +static void IPArp(unsigned char ipAddress[4]) +{ + IPFrame *frame; + uint8 *packetOut; + + frame = IPFrameGet(0); + if(frame == NULL) + return; + packetOut = frame->packet; + memset(packetOut, 0, 512); + memset(packetOut+ETHERNET_DEST, 0xff, 6); + memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); + packetOut[ETHERNET_FRAME_TYPE] = 0x08; + packetOut[ETHERNET_FRAME_TYPE+1] = 0x06; + packetOut[ARP_HARD_TYPE+1] = 0x01; + packetOut[ARP_PROT_TYPE] = 0x08; + packetOut[ARP_HARD_SIZE] = 0x06; + packetOut[ARP_PROT_SIZE] = 0x04; + packetOut[ARP_OP+1] = 1; + memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6); + memcpy(packetOut+ARP_IP_SENDER, ipAddressPlasma, 4); + memcpy(packetOut+ARP_IP_TARGET, ipAddress, 4); + IPSendPacket(NULL, frame, 60); +} + + +static void IPDhcp(const unsigned char *packet, int length, int state) +{ + uint8 *packetOut, *ptr; + const uint8 *ptr2; + IPFrame *frame; + static int request=0; + + if(state == 1) + { + //Create DHCP Discover + frame = IPFrameGet(0); + if(frame == NULL) + return; + packetOut = frame->packet; + memset(packetOut, 0, 512); + memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover)); + memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); + memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6); + memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions)); + memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6); + IPSendPacket(NULL, frame, 400); + request = DHCP_DISCOVER; + DhcpRetrySeconds = 2; + } + else if(state == 2 && memcmp(packet+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6) == 0) + { + if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_OFFER && request == DHCP_DISCOVER) + { + //Process DHCP Offer and send DHCP Request + frame = IPFrameGet(0); + if(frame == NULL) + return; + packetOut = frame->packet; + memset(packetOut, 0, 512); + memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover)); + memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); + memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6); + memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions)); + memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6); + request = DHCP_REQUEST; + packetOut[DHCP_MAGIC_COOKIE+6] = DHCP_REQUEST; + ptr = packetOut+DHCP_MAGIC_COOKIE+sizeof(dhcpOptions)-1; + ptr[0] = DHCP_REQUEST_IP; + ptr[1] = 4; + memcpy(ptr+2, packet+DHCP_YOUR_IP, 4); + ptr[6] = DHCP_REQUEST_SERV_IP; + ptr[7] = 4; + memcpy(ptr+8, packet+DHCP_SERVER_IP, 4); + ptr[12] = DHCP_END_OPTION; + IPSendPacket(NULL, frame, 400); + } + else if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_ACK && request == DHCP_REQUEST) + { + //Process DHCP Ack + request = 0; + DhcpRetrySeconds = 3600*4; + memcpy(ipAddressPlasma, packet+DHCP_YOUR_IP, 4); + printf("IP=%d.%d.%d.%d ", ipAddressPlasma[0], ipAddressPlasma[1], + ipAddressPlasma[2], ipAddressPlasma[3]); + memcpy(ipAddressGateway, packet+DHCP_GATEWAY_IP, 4); + if(ipAddressGateway[0] == 0 && ipAddressGateway[1] == 0 && + ipAddressGateway[2] == 0 && ipAddressGateway[3] == 0) + memcpy(ipAddressGateway, packet+DHCP_SERVER_IP, 4); + printf("GW=%d.%d.%d.%d ", ipAddressGateway[0], ipAddressGateway[1], + ipAddressGateway[2], ipAddressGateway[3]); + memcpy(ethernetAddressGateway, packet+ETHERNET_SOURCE, 6); + ptr2 = packet+DHCP_MAGIC_COOKIE+4; + while(ptr2[0] != DHCP_END_OPTION && (int)(ptr2 - packet) < length) + { + if(ptr2[0] == DHCP_PARAM_DNS) + { + ipAddressDns = (ptr2[2] << 24) | (ptr2[3] << 16) | (ptr2[4] << 8) | ptr2[5]; + printf("DNS=%d.%d.%d.%d ", ptr2[2], ptr2[3], ptr2[4], ptr2[5]); + } + ptr2 += ptr2[1] + 2; + } + + //Check if DHCP reply came from gateway + if(memcmp(packet+IP_SOURCE, ipAddressGateway, 4)) + { + memset(ethernetAddressGateway, 0xff, 6); + IPArp(ipAddressGateway); //Send ARP to gateway + } + } + } +} + + +uint32 IPAddressSelf(void) +{ + return (ipAddressPlasma[0] << 24) | (ipAddressPlasma[1] << 16) | + (ipAddressPlasma[2] << 8) | ipAddressPlasma[3]; +} + + +static int IPProcessTCPPacket(IPFrame *frameIn) +{ + uint32 seq, ack; + int length, ip_length, bytes, rc=0, notify=0; + IPSocket *socket, *socketNew; + IPFrame *frameOut, *frame2, *framePrev; + uint8 *packet, *packetOut; + + packet = frameIn->packet; + length = frameIn->length; + + ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1]; + seq = (packet[TCP_SEQ] << 24) | (packet[TCP_SEQ+1] << 16) | + (packet[TCP_SEQ+2] << 8) | packet[TCP_SEQ+3]; + ack = (packet[TCP_ACK] << 24) | (packet[TCP_ACK+1] << 16) | + (packet[TCP_ACK+2] << 8) | packet[TCP_ACK+3]; + + //Check if start of connection + if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == TCP_FLAGS_SYN) + { + if(IPVerbose) + printf("S"); + //Check if duplicate SYN + for(socket = SocketHead; socket; socket = socket->next) + { + if(socket->state != IP_LISTEN && + packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && + memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 && + memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0) + { + if(IPVerbose) + printf("s"); + return 0; + } + } + + //Find an open port + for(socket = SocketHead; socket; socket = socket->next) + { + if(socket->state == IP_LISTEN && + packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && + memcmp(packet+TCP_DEST_PORT, socket->headerRcv+TCP_DEST_PORT, 2) == 0) + { + //Create a new socket + frameOut = IPFrameGet(FRAME_COUNT_SYNC); + if(frameOut == NULL) + return 0; + socketNew = (IPSocket*)malloc(sizeof(IPSocket)); + if(socketNew == NULL) + return 0; + memcpy(socketNew, socket, sizeof(IPSocket)); + socketNew->state = IP_TCP; + socketNew->timeout = SOCKET_TIMEOUT; + socketNew->ack = seq; + socketNew->ackProcessed = seq + 1; + socketNew->seq = socketNew->ack + 0x12345678; + socketNew->seqReceived = socketNew->seq; + socketNew->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1]; + + //Send ACK + packetOut = frameOut->packet; + EthernetCreateResponse(packetOut, packet, length); + memcpy(socketNew->headerRcv, packet, TCP_SEQ); + memcpy(socketNew->headerSend, packetOut, TCP_SEQ); + packetOut[TCP_FLAGS] = TCP_FLAGS_SYN | TCP_FLAGS_ACK; + ++socketNew->ack; + packetOut[TCP_DATA] = 2; //maximum segment size = 536 + packetOut[TCP_DATA+1] = 4; + packetOut[TCP_DATA+2] = 2; + packetOut[TCP_DATA+3] = 24; + TCPSendPacket(socketNew, frameOut, TCP_DATA+4); + ++socketNew->seq; + + //Add socket to linked list + OS_MutexPend(IPMutex); + socketNew->next = SocketHead; + socketNew->prev = NULL; + if(SocketHead) + SocketHead->prev = socketNew; + SocketHead = socketNew; + OS_MutexPost(IPMutex); + if(socketNew->funcPtr) + OS_Job(socketNew->funcPtr, socketNew, 0, 0); + return 0; + } + } + + //Send reset + frameOut = IPFrameGet(0); + if(frameOut == NULL) + return 0; + packetOut = frameOut->packet; + EthernetCreateResponse(packetOut, packet, TCP_DATA); + memset(packetOut+TCP_SEQ, 0, 4); + ++seq; + packetOut[TCP_ACK] = (uint8)(seq >> 24); + packetOut[TCP_ACK+1] = (uint8)(seq >> 16); + packetOut[TCP_ACK+2] = (uint8)(seq >> 8); + packetOut[TCP_ACK+3] = (uint8)seq; + packetOut[TCP_HEADER_LENGTH] = 0x50; + packetOut[TCP_FLAGS] = TCP_FLAGS_RST; + IPSendPacket(NULL, frameOut, TCP_DATA); + return 0; + } + + //Find an open socket + for(socket = SocketHead; socket; socket = socket->next) + { + if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && + memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 && + memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0) + { + break; + } + } + if(socket == NULL) + { + return 0; + } + + //Determine window + socket->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1]; + bytes = ip_length - (TCP_DATA - IP_VERSION_LENGTH); + + //Check if packets can be removed from retransmition list + if(packet[TCP_FLAGS] & TCP_FLAGS_ACK) + { + if(ack != socket->seqReceived) + { + OS_MutexPend(IPMutex); + for(frame2 = FrameResendHead; frame2; ) + { + framePrev = frame2; + frame2 = frame2->next; + if(framePrev->socket == socket && (int)(ack - framePrev->seqEnd) >= 0) + { + //Remove packet from retransmition queue + if(socket->timeout) + socket->timeout = socket->timeoutReset; + FrameRemove(&FrameResendHead, &FrameResendTail, framePrev); + FrameFree(framePrev); + } + } + OS_MutexPost(IPMutex); + socket->seqReceived = ack; + socket->resentDone = 0; + } + else if(ack == socket->seqReceived && bytes == 0 && + (packet[TCP_FLAGS] & (TCP_FLAGS_RST | TCP_FLAGS_FIN)) == 0 && + socket->resentDone == 0) + { + //Detected that packet was lost, resend all + if(IPVerbose) + printf("A"); + OS_MutexPend(IPMutex); + for(frame2 = FrameResendHead; frame2; ) + { + framePrev = frame2; + frame2 = frame2->next; + if(framePrev->socket == socket) + { + //Remove packet from retransmition queue + FrameRemove(&FrameResendHead, &FrameResendTail, framePrev); + IPSendFrame(framePrev); + } + } + OS_MutexPost(IPMutex); + socket->resentDone = 1; + } + } + + //Check if SYN/ACK + if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == + (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) + { + //Ack SYN/ACK + socket->ack = seq + 1; + socket->ackProcessed = seq + 1; + frameOut = IPFrameGet(FRAME_COUNT_SEND); + if(frameOut) + { + frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK; + TCPSendPacket(socket, frameOut, TCP_DATA); + } + if(socket->funcPtr) + OS_Job(socket->funcPtr, socket, 0, 0); + return 0; + } + if(packet[TCP_HEADER_LENGTH] != 0x50) + { + if(IPVerbose) + printf("length error\n"); + return 0; + } + + //Check if RST flag set + if(packet[TCP_FLAGS] & TCP_FLAGS_RST) + { + notify = 1; + IPClose2(socket); + } + //Copy packet into socket + else if(socket->ack == seq && bytes > 0) + { + //Insert packet into socket linked list + notify = 1; + if(socket->timeout) + socket->timeout = socket->timeoutReset; + if(IPVerbose) + printf("D"); + if(frameIn->length > ip_length + IP_VERSION_LENGTH) + frameIn->length = (uint16)(ip_length + IP_VERSION_LENGTH); + FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn); + socket->ack += bytes; + + //Ack data + frameOut = IPFrameGet(FRAME_COUNT_SEND); + if(frameOut) + { + frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK; + TCPSendPacket(socket, frameOut, TCP_DATA); + } + + //Using frame + rc = 1; + } + else if(bytes) + { + //Ack with current offset since data missing + frameOut = IPFrameGet(FRAME_COUNT_SEND); + if(frameOut) + { + frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK; + TCPSendPacket(socket, frameOut, TCP_DATA); + } + } + + //Check if FIN flag set + if(packet[TCP_FLAGS] & TCP_FLAGS_FIN && socket->ack >= seq) + { + notify = 1; + socket->timeout = SOCKET_TIMEOUT; + if(IPVerbose) + printf("F"); + frameOut = IPFrameGet(0); + if(frameOut == NULL) + return 0; + packetOut = frameOut->packet; + packetOut[TCP_FLAGS] = TCP_FLAGS_ACK; + ++socket->ack; + TCPSendPacket(socket, frameOut, TCP_DATA); + if(socket->state == IP_FIN_SERVER) + socket->timeout = SOCKET_TIMEOUT; + else if(socket->state == IP_TCP) + socket->state = IP_FIN_CLIENT; + } + + //Notify application + if(socket->funcPtr && notify) + OS_Job(socket->funcPtr, socket, 0, 0); + return rc; +} + + +int IPProcessEthernetPacket(IPFrame *frameIn, int length) +{ + int ip_length, rc; + IPSocket *socket; + IPFrame *frameOut; + uint8 *packet, *packetOut; + + packet = frameIn->packet; + frameIn->length = (uint16)length; + + if(packet[ETHERNET_FRAME_TYPE] != 0x08 || frameIn->length > PACKET_SIZE) + return 0; //wrong ethernet type, packet not used + + //ARP? + if(packet[ETHERNET_FRAME_TYPE+1] == 0x06) + { + //Check if ARP reply + if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) == 0 && + packet[ARP_OP+1] == 2) + { + memcpy(ArpCache[ArpCacheIndex].ip, packet+ARP_IP_SENDER, 4); + memcpy(ArpCache[ArpCacheIndex].mac, packet+ARP_ETHERNET_SENDER, 6); + if(++ArpCacheIndex >= sizeof(ArpCache) / sizeof(ArpCache_t)) + ArpCacheIndex = 0; + if(memcmp(packet+ARP_IP_SENDER, ipAddressGateway, 4) == 0) + { + //Found MAC address for gateway + memcpy(ethernetAddressGateway, packet+ARP_ETHERNET_SENDER, 6); + } + return 0; + } + + //Check if ARP request + if(packet[ARP_OP] != 0 || packet[ARP_OP+1] != 1 || + memcmp(packet+ARP_IP_TARGET, ipAddressPlasma, 4)) + return 0; + //Create ARP response + frameOut = IPFrameGet(0); + if(frameOut == NULL) + return 0; + packetOut = frameOut->packet; + memcpy(packetOut, packet, frameIn->length); + memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6); + memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); + packetOut[ARP_OP+1] = 2; //ARP reply + memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6); + memcpy(packetOut+ARP_IP_SENDER, packet+ARP_IP_TARGET, 4); + memcpy(packetOut+ARP_ETHERNET_TARGET, packet+ARP_ETHERNET_SENDER, 6); + memcpy(packetOut+ARP_IP_TARGET, packet+ARP_IP_SENDER, 4); + IPSendPacket(NULL, frameOut, frameIn->length); + return 0; + } + + //Check if proper type of packet + ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1]; + if(frameIn->length < UDP_DATA || ip_length > frameIn->length - IP_VERSION_LENGTH) + return 0; + if(packet[ETHERNET_FRAME_TYPE+1] != 0x00 || + packet[IP_VERSION_LENGTH] != 0x45) + return 0; + + //Check if DHCP reply + if(packet[IP_PROTOCOL] == 0x11 && + packet[UDP_SOURCE_PORT] == 0 && packet[UDP_SOURCE_PORT+1] == 67 && + packet[UDP_DEST_PORT] == 0 && packet[UDP_DEST_PORT+1] == 68) + { + IPDhcp(packet, frameIn->length, 2); //DHCP reply + return 0; + } + + //Check if correct destination address + if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) || + memcmp(packet+IP_DEST, ipAddressPlasma, 4)) + return 0; + rc = EthernetVerifyChecksums(packet, frameIn->length); +#ifndef WIN32 + if(rc && FrameSendFunc) + { + printf("C "); + return 0; + } +#endif + + //PING request? + if(packet[IP_PROTOCOL] == 1) + { + if(packet[PING_TYPE] == 0) //PING reply + { + for(socket = SocketHead; socket; socket = socket->next) + { + if(socket->state == IP_PING && + memcmp(packet+IP_SOURCE, socket->headerSend+IP_DEST, 4) == 0) + { + OS_Job(socket->funcPtr, socket, 0, 0); + return 0; + } + } + } + if(packet[PING_TYPE] != 8) + return 0; + frameOut = IPFrameGet(FRAME_COUNT_SEND); + if(frameOut == NULL) + return 0; + packetOut = frameOut->packet; + EthernetCreateResponse(packetOut, packet, frameIn->length); + frameOut->packet[PING_TYPE] = 0; //PING reply + IPSendPacket(NULL, frameOut, frameIn->length); + return 0; + } + + //TCP packet? + if(packet[IP_PROTOCOL] == 0x06) + { + return IPProcessTCPPacket(frameIn); + } + + //UDP packet? + if(packet[IP_PROTOCOL] == 0x11) + { + //Find open socket + for(socket = SocketHead; socket; socket = socket->next) + { + if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && + memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 && + memcmp(packet+UDP_SOURCE_PORT, socket->headerRcv+UDP_SOURCE_PORT, 2) == 0) + { + break; + } + } + + if(socket == NULL) + { + //Find listening socket + for(socket = SocketHead; socket; socket = socket->next) + { + if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && + memcmp(packet+UDP_DEST_PORT, socket->headerRcv+UDP_DEST_PORT, 2) == 0) + { + EthernetCreateResponse(socket->headerSend, packet, UDP_DATA); + break; + } + } + } + + if(socket) + { + if(IPVerbose) + printf("U"); + FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn); + OS_Job(socket->funcPtr, socket, 0, 0); + return 1; + } + } + return 0; +} + + +#ifndef WIN32 +static void IPMainThread(void *arg) +{ + uint32 message[4]; + int rc; + IPFrame *frame, *frameOut=NULL; + uint32 ticks, ticksLast; + (void)arg; + + ticksLast = OS_ThreadTime(); + memset(message, 0, sizeof(message)); + + for(;;) + { + Led(7, 0); + rc = OS_MQueueGet(IPMQueue, message, 10); + if(rc == 0) + { + frame = (IPFrame*)message[1]; + if(message[0] == 0) //frame received + { + Led(7, 1); + frame->length = (uint16)message[2]; + rc = IPProcessEthernetPacket(frame, frame->length); + if(rc == 0) + FrameFree(frame); + } + else if(message[0] == 1) //frame sent + { + Led(7, 2); + assert(frame == frameOut); + IPFrameReschedule(frame); + frameOut = NULL; + } + else if(message[0] == 2) //frame ready to send + { + } + } + + if(frameOut == NULL) + { + OS_MutexPend(IPMutex); + frameOut = FrameSendTail; + if(frameOut) + FrameRemove(&FrameSendHead, &FrameSendTail, frameOut); + OS_MutexPost(IPMutex); + if(frameOut) + { + Led(7, 4); + UartPacketSend(frameOut->packet, frameOut->length); + } + } + + ticks = OS_ThreadTime(); + if(ticks - ticksLast > 100) + { + IPTick(); + ticksLast = ticks; + } + } +} +#endif + + +uint8 *MyPacketGet(void) +{ + return (uint8*)IPFrameGet(FRAME_COUNT_RCV); +} + + +//Set FrameSendFunction only if single threaded +void IPInit(IPFuncPtr frameSendFunction, uint8 macAddress[6], char name[6]) +{ + int i; + IPFrame *frame; + + if(macAddress) + memcpy(ethernetAddressPlasma, macAddress, 6); + if(name) + memcpy(dhcpOptions+18, name, 6); + FrameSendFunc = frameSendFunction; + IPMutex = OS_MutexCreate("IPSem"); + IPMQueue = OS_MQueueCreate("IPMQ", FRAME_COUNT*2, 32); + for(i = 0; i < FRAME_COUNT; ++i) + { + frame = (IPFrame*)malloc(sizeof(IPFrame)); + memset(frame, 0, sizeof(IPFrame)); + frame->next = FrameFreeHead; + frame->prev = NULL; + FrameFreeHead = frame; + } + FrameFreeCount = FRAME_COUNT; +#ifndef WIN32 + UartPacketConfig(MyPacketGet, PACKET_SIZE, IPMQueue); + if(frameSendFunction == NULL) + IPThread = OS_ThreadCreate("TCP/IP", IPMainThread, NULL, 240, 6000); +#endif + IPDhcp(NULL, 360, 1); //Send DHCP request +} + + +//To open a socket for listen set ipAddress to 0 +IPSocket *IPOpen(IPMode_e mode, uint32 ipAddress, uint32 port, IPFuncPtr funcPtr) +{ + IPSocket *socket; + uint8 *ptrSend, *ptrRcv; + IPFrame *frame; + static int portSource=0x1007; + + socket = (IPSocket*)malloc(sizeof(IPSocket)); + if(socket == NULL) + return socket; + memset(socket, 0, sizeof(IPSocket)); + socket->prev = NULL; + socket->state = IP_LISTEN; + socket->timeout = 0; + socket->timeoutReset = SOCKET_TIMEOUT; + socket->frameReadHead = NULL; + socket->frameReadTail = NULL; + socket->readOffset = 0; + socket->funcPtr = funcPtr; + socket->userData = 0; + socket->userFunc = NULL; + socket->userPtr = NULL; + socket->seqWindow = 2048; + ptrSend = socket->headerSend; + ptrRcv = socket->headerRcv; + + if(ipAddress == 0) + { + //Setup listing port + socket->headerRcv[TCP_DEST_PORT] = (uint8)(port >> 8); + socket->headerRcv[TCP_DEST_PORT+1] = (uint8)port; + } + else + { + //Setup sending packet + memset(ptrSend, 0, UDP_LENGTH); + memset(ptrRcv, 0, UDP_LENGTH); + + //Setup Ethernet + if(ipAddress != IPAddressSelf()) + memcpy(ptrSend+ETHERNET_DEST, ethernetAddressGateway, 6); + else + memcpy(ptrSend+ETHERNET_DEST, ethernetAddressPlasma, 6); + memcpy(ptrSend+ETHERNET_SOURCE, ethernetAddressPlasma, 6); + ptrSend[ETHERNET_FRAME_TYPE] = 0x08; + + //Setup IP + ptrSend[IP_VERSION_LENGTH] = 0x45; + ptrSend[IP_TIME_TO_LIVE] = 0x80; + + //Setup IP addresses + memcpy(ptrSend+IP_SOURCE, ipAddressPlasma, 4); + ptrSend[IP_DEST] = (uint8)(ipAddress >> 24); + ptrSend[IP_DEST+1] = (uint8)(ipAddress >> 16); + ptrSend[IP_DEST+2] = (uint8)(ipAddress >> 8); + ptrSend[IP_DEST+3] = (uint8)ipAddress; + ptrRcv[IP_SOURCE] = (uint8)(ipAddress >> 24); + ptrRcv[IP_SOURCE+1] = (uint8)(ipAddress >> 16); + ptrRcv[IP_SOURCE+2] = (uint8)(ipAddress >> 8); + ptrRcv[IP_SOURCE+3] = (uint8)ipAddress; + memcpy(ptrRcv+IP_DEST, ipAddressPlasma, 4); + + //Setup ports + ptrSend[TCP_SOURCE_PORT] = (uint8)(portSource >> 8); + ptrSend[TCP_SOURCE_PORT+1] = (uint8)portSource; + ptrSend[TCP_DEST_PORT] = (uint8)(port >> 8); + ptrSend[TCP_DEST_PORT+1] = (uint8)port; + ptrRcv[TCP_SOURCE_PORT] = (uint8)(port >> 8); + ptrRcv[TCP_SOURCE_PORT+1] = (uint8)port; + ptrRcv[TCP_DEST_PORT] = (uint8)(portSource >> 8); + ptrRcv[TCP_DEST_PORT+1] = (uint8)portSource; + ++portSource; + } + + if(mode == IP_MODE_TCP) + { + if(ipAddress) + socket->state = IP_TCP; + else + socket->state = IP_LISTEN; + ptrSend[IP_PROTOCOL] = 0x06; //TCP + ptrRcv[IP_PROTOCOL] = 0x06; + } + else if(mode == IP_MODE_UDP) + { + socket->state = IP_UDP; + ptrSend[IP_PROTOCOL] = 0x11; //UDP + ptrRcv[IP_PROTOCOL] = 0x11; + } + else if(mode == IP_MODE_PING) + { + socket->state = IP_PING; + ptrSend[IP_PROTOCOL] = 0x01; //PING + memset(ptrSend+PING_TYPE, 0, 8); + ptrSend[PING_TYPE] = 8; //SEND + } + + //Add socket to linked list + OS_MutexPend(IPMutex); + socket->next = SocketHead; + socket->prev = NULL; + if(SocketHead) + SocketHead->prev = socket; + SocketHead = socket; + OS_MutexPost(IPMutex); + + if(mode == IP_MODE_TCP && ipAddress) + { + //Send TCP SYN + socket->seq = 0x01234567; + frame = IPFrameGet(0); + if(frame) + { + frame->packet[TCP_FLAGS] = TCP_FLAGS_SYN; + frame->packet[TCP_DATA] = 2; //maximum segment size = 536 + frame->packet[TCP_DATA+1] = 4; + frame->packet[TCP_DATA+2] = 2; + frame->packet[TCP_DATA+3] = 24; + TCPSendPacket(socket, frame, TCP_DATA+4); + ++socket->seq; + } + } + return socket; +} + + +void IPWriteFlush(IPSocket *socket) +{ + uint8 *packetOut; + if(socket->frameSend && socket->state != IP_UDP && + socket->state != IP_PING) + { + packetOut = socket->frameSend->packet; + packetOut[TCP_FLAGS] = TCP_FLAGS_ACK | TCP_FLAGS_PSH; + TCPSendPacket(socket, socket->frameSend, TCP_DATA + socket->sendOffset); + socket->seq += socket->sendOffset; + socket->frameSend = NULL; + socket->sendOffset = 0; + } +} + + +uint32 IPWrite(IPSocket *socket, const uint8 *buf, uint32 length) +{ + IPFrame *frameOut; + uint8 *packetOut; + uint32 bytes, count=0, tries=0; + int offset; + OS_Thread_t *self; + + if(socket->state > IP_TCP) + return 0; + + if(socket->timeout) + socket->timeout = socket->timeoutReset; + +#ifdef INCLUDE_FILESYS + if(socket->fileOut) //override stdout + return fwrite((char*)buf, 1, length, socket->fileOut); +#endif + + //printf("IPWrite(0x%x, %d)", Socket, Length); + self = OS_ThreadSelf(); + while(length) + { + //Rate limit output + if(socket->seq - socket->seqReceived >= SEND_WINDOW) + { + //printf("l(%d,%d,%d) ", socket->seq - socket->seqReceived, socket->seq, socket->seqReceived); + if(self != IPThread && ++tries < 200) + { + OS_ThreadSleep(1); + continue; + } + } + tries = 0; + while(socket->frameSend == NULL) + { + socket->frameSend = IPFrameGet(FRAME_COUNT_SEND); + socket->sendOffset = 0; + if(socket->frameSend == NULL) + { + //printf("L"); + if(self == IPThread || ++tries > 200) + break; + else + OS_ThreadSleep(1); + } + } + frameOut = socket->frameSend; + offset = socket->sendOffset; + if(frameOut == NULL) + break; + packetOut = frameOut->packet; + + if(socket->state == IP_PING) + { + bytes = length; + memcpy(packetOut, socket->headerSend, PING_DATA); + memcpy(packetOut+PING_DATA, buf, bytes); + IPSendPacket(socket, socket->frameSend, PING_DATA + bytes); + socket->frameSend = NULL; + } + else if(socket->state != IP_UDP) + { + bytes = 512 - offset; + if(bytes > length) + bytes = length; + socket->sendOffset += bytes; + memcpy(packetOut+TCP_DATA+offset, buf, bytes); + if(socket->sendOffset >= 512) + IPWriteFlush(socket); + //if(Socket->seq - Socket->seqReceived > Socket->seqWindow) + //{ + // printf("W"); + // OS_ThreadSleep(10); + //} + } + else //UDP + { + bytes = length; + memcpy(packetOut+UDP_DATA+offset, buf, bytes); + memcpy(packetOut, socket->headerSend, UDP_LENGTH); + IPSendPacket(socket, socket->frameSend, UDP_DATA + bytes); + socket->frameSend = NULL; + } + count += bytes; + buf += bytes; + length -= bytes; + } + return count; +} + + +uint32 IPRead(IPSocket *socket, uint8 *buf, uint32 length) +{ + IPFrame *frame, *frame2; + int count=0, bytes, offset; + +#ifdef INCLUDE_FILESYS + if(socket->fileIn) //override stdin + { + bytes = fread(buf, 1, 1, socket->fileIn); + if(bytes == 0) + { + buf[0] = 0; + fclose(socket->fileIn); + socket->fileIn = NULL; + bytes = 1; + } + return bytes; + } +#endif + + if(socket->state == IP_UDP) + offset = UDP_DATA; + else + offset = TCP_DATA; + + OS_MutexPend(IPMutex); + for(frame = socket->frameReadTail; length && frame; ) + { + bytes = frame->length - offset - socket->readOffset; + if(bytes > (int)length) + bytes = length; + memcpy(buf, frame->packet + offset + socket->readOffset, bytes); + buf += bytes; + socket->readOffset += bytes; + length -= bytes; + count += bytes; + + //Check if done with packet + frame2 = frame; + frame = frame->prev; + if(socket->readOffset == frame2->length - offset) + { + //Remove packet from socket linked list + socket->readOffset = 0; + FrameRemove(&socket->frameReadHead, &socket->frameReadTail, frame2); + socket->ackProcessed += frame2->length - offset; + if(socket->state == IP_TCP && + socket->ack - socket->ackProcessed > RECEIVE_WINDOW - 2048) + { + //Update receive window for flow control + frame2->packet[TCP_FLAGS] = TCP_FLAGS_ACK; + TCPSendPacket(socket, frame2, TCP_DATA); + } + else + FrameFree(frame2); + } + } + OS_MutexPost(IPMutex); + return count; +} + + +static void IPClose2(IPSocket *socket) +{ + IPFrame *frame, *framePrev; + + //printf("IPClose2(%x) ", (int)socket); + + OS_MutexPend(IPMutex); + + //Remove pending packets + for(frame = FrameSendHead; frame; ) + { + framePrev = frame; + frame = frame->next; + if(framePrev->socket == socket) + { + FrameRemove(&FrameResendHead, &FrameResendTail, framePrev); + FrameFree(framePrev); + } + } + + //Remove packets from retransmision list + for(frame = FrameResendHead; frame; ) + { + framePrev = frame; + frame = frame->next; + if(framePrev->socket == socket) + { + FrameRemove(&FrameResendHead, &FrameResendTail, framePrev); + FrameFree(framePrev); + } + } + + //Remove packets from socket read linked list + for(frame = socket->frameReadHead; frame; ) + { + framePrev = frame; + frame = frame->next; + FrameRemove(&socket->frameReadHead, &socket->frameReadTail, framePrev); + FrameFree(framePrev); + } + + //Give application time to stop using socket + socket->timeout = SOCKET_TIMEOUT; + socket->state = IP_CLOSED; + + OS_MutexPost(IPMutex); +} + + +void IPClose(IPSocket *socket) +{ + IPFrame *frameOut; + + //printf("IPClose(%x) ", (int)socket); + + IPWriteFlush(socket); + if(socket->state <= IP_UDP) + { + IPClose2(socket); + return; + } + frameOut = IPFrameGet(0); + if(frameOut == NULL) + return; + frameOut->packet[TCP_FLAGS] = TCP_FLAGS_FIN | TCP_FLAGS_ACK; + TCPSendPacket(socket, frameOut, TCP_DATA); + ++socket->seq; + socket->timeout = SOCKET_TIMEOUT; + socket->timeoutReset = SOCKET_TIMEOUT; + socket->state = IP_FIN_SERVER; +} + + +void IPPrintf(IPSocket *socket, char *message, + int arg0, int arg1, int arg2, int arg3) +{ + char buf[500]; + if(socket == NULL) + { + printf(message, arg0, arg1, arg2, arg3); + return; + } + if(strcmp(message, "%s") == 0) + IPWrite(socket, (uint8*)arg0, (int)strlen((char*)arg0)); + else + { + sprintf(buf, message, arg0, arg1, arg2, arg3, 0, 0, 0, 0); + IPWrite(socket, (uint8*)buf, (int)strlen(buf)); + } + if(socket->dontFlush == 0 || strstr(message, "\n")) + IPWriteFlush(socket); +} + + +void IPTick(void) +{ + IPFrame *frame, *frame2; + IPSocket *socket, *socket2; + unsigned long ticks; + static unsigned long ticksPrev=0, ticksPrev2=0; + + ticks = OS_ThreadTime(); +#ifdef WIN32 + ticks = ticksPrev + 100; +#endif + if(ticks - ticksPrev >= 95) + { + if(IPVerbose && (Seconds % 60) == 0) + { + if(FrameFreeCount >= FRAME_COUNT-1) + printf("T"); + else + printf("T(%d)", FrameFreeCount); + } + ++Seconds; + if(--DhcpRetrySeconds <= 0) + IPDhcp(NULL, 400, 1); //DHCP request + } + + OS_MutexPend(IPMutex); + + //Retransmit timeout packets + for(frame = FrameResendHead; frame; ) + { + frame2 = frame; + frame = frame->next; + frame2->timeout = (short)(frame2->timeout - (ticks - ticksPrev2)); + if(--frame2->timeout <= 0) + { + if(IPVerbose) + printf("r" /*"(%x,%x,%d,%d,%d)"*/, (int)frame2, (int)frame2->socket, + frame2->retryCnt, frame2->length - TCP_DATA, + frame2->socket->state); + FrameRemove(&FrameResendHead, &FrameResendTail, frame2); + if(frame2->retryCnt < 4 && frame2->socket->state < IP_CLOSED) + IPSendFrame(frame2); + else + { + if(frame2->socket->state == IP_TCP) + IPClose(frame2->socket); + FrameFree(frame2); + } + } + } + + if(ticks - ticksPrev >= 95) + { + //Close timed out sockets + for(socket = SocketHead; socket; ) + { + socket2 = socket; + socket = socket->next; + if(socket2->timeout && --socket2->timeout == 0) + { + socket2->timeout = SOCKET_TIMEOUT; + if(socket2->state <= IP_TCP || socket2->state == IP_FIN_CLIENT) + IPClose(socket2); + else if(socket2->state != IP_CLOSED) + IPClose2(socket2); + else + { + if(socket2->prev == NULL) + SocketHead = socket2->next; + else + socket2->prev->next = socket2->next; + if(socket2->next) + socket2->next->prev = socket2->prev; + //printf("freeSocket(%x) ", (int)socket2); + free(socket2); + } + } + } + ticksPrev = ticks; + } + OS_MutexPost(IPMutex); + ticksPrev2 = ticks; +} + + +static void DnsCallback(IPSocket *socket) +{ + uint8 buf[200], *ptr; + uint32 ipAddress; + int bytes; + + memset(buf, 0, sizeof(buf)); + bytes = IPRead(socket, buf, sizeof(buf)); + if(buf[DNS_NUM_ANSWERS_RR+1]) + { + for(ptr = buf + DNS_QUESTIONS; ptr + 14 <= buf + bytes; ++ptr) + { + if(ptr[0] == 0 && ptr[1] == 1 && ptr[2] == 0 && ptr[3] == 1 && + ptr[8] == 0 && ptr[9] == 4) + { + ipAddress = (ptr[10] << 24) | (ptr[11] << 16) | (ptr[12] << 8) | ptr[13]; + printf("ipAddress = %d.%d.%d.%d\n", ptr[10], ptr[11], ptr[12], ptr[13]); + socket->userData = ipAddress; + if(socket->userFunc) + { + socket->userFunc(socket, ipAddress, socket->userPtr); + } + break; + } + } + } + IPClose(socket); +} + + +void IPResolve(char *name, IPFuncPtr resolvedFunc, void *arg) +{ + uint8 buf[200], *ptr; + int length, i; + IPSocket *socket; + + socket = IPOpen(IP_MODE_UDP, ipAddressDns, DNS_PORT, DnsCallback); + memset(buf, 0, sizeof(buf)); + buf[DNS_ID+1] = 1; + buf[DNS_FLAGS] = 1; + buf[DNS_NUM_QUESTIONS+1] = 1; + + //Setup name + ptr = buf + DNS_QUESTIONS; + strncpy((char*)ptr+1, name, 100); + ptr[0] = 1; + while(ptr[0]) + { + for(i = 0; i < 100; ++i) + { + if(ptr[i+1] == '.' || ptr[i+1] == 0) + { + ptr[0] = (uint8)i; + ptr += i+1; + break; + } + } + } + ++ptr; + ptr[1] = DNS_QUERY_TYPE_IP; + ptr[3] = DNS_QUERY_CLASS; + length = (int)(ptr - buf) + 4; + if(length < 60) + length = 60; + + socket->userFunc = (IPFuncPtr)resolvedFunc; + socket->userPtr = arg; + socket->userData = 0; + IPWrite(socket, buf, length); +} + diff --git a/kernel/tcpip.h b/kernel/tcpip.h new file mode 100644 index 0000000..9d5d626 --- /dev/null +++ b/kernel/tcpip.h @@ -0,0 +1,131 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma TCP/IP Protocol Stack + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 4/22/06 + * FILENAME: tcpip.h + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma TCP/IP Protocol Stack + *--------------------------------------------------------------------*/ +#ifndef __TCPIP_H__ +#define __TCPIP_H__ +#define PACKET_SIZE 600 +#define FRAME_COUNT 100 +#define FRAME_COUNT_SYNC 50 +#define FRAME_COUNT_SEND 10 +#define FRAME_COUNT_RCV 5 +#define RETRANSMIT_TIME 110 +#define SOCKET_TIMEOUT 15 +#define SEND_WINDOW 7000 +#define RECEIVE_WINDOW 5120 + +typedef enum IPMode_e { + IP_MODE_UDP, + IP_MODE_TCP, + IP_MODE_PING +} IPMode_e; + +typedef enum IPState_e { + IP_LISTEN, + IP_PING, + IP_UDP, + IP_SYN, + IP_TCP, + IP_FIN_CLIENT, + IP_FIN_SERVER, + IP_CLOSED +} IPState_e; + +typedef void (*IPFuncPtr)(); + +typedef struct IPFrame { + uint8 packet[PACKET_SIZE]; + struct IPFrame *next, *prev; + struct IPSocket *socket; + uint32 seqEnd; + uint16 length; + short timeout; + uint8 state, retryCnt; +} IPFrame; + +typedef struct IPSocket { + struct IPSocket *next, *prev; + IPState_e state; + uint32 seq; + uint32 seqReceived; + uint32 seqWindow; + uint32 ack; + uint32 ackProcessed; + uint32 timeout; + uint32 timeoutReset; + int resentDone; + int dontFlush; + uint8 headerSend[38]; + uint8 headerRcv[38]; + struct IPFrame *frameReadHead; + struct IPFrame *frameReadTail; + int readOffset; + struct IPFrame *frameSend; + int sendOffset; + void *fileOut; + void *fileIn; + IPFuncPtr funcPtr; + IPFuncPtr userFunc; + void *userPtr; + void *userPtr2; + uint32 userData; + uint32 userData2; +} IPSocket; + +//ethernet.c +void EthernetSendPacket(const unsigned char *packet, int length); //Windows +void EthernetInit(unsigned char MacAddress[6]); +int EthernetReceive(unsigned char *buffer, int length); +void EthernetTransmit(unsigned char *buffer, int length); + +//tcpip.c +void IPInit(IPFuncPtr frameSendFunction, uint8 macAddress[6], char name[6]); +IPFrame *IPFrameGet(int freeCount); +int IPProcessEthernetPacket(IPFrame *frameIn, int length); +void IPTick(void); + +IPSocket *IPOpen(IPMode_e mode, uint32 ipAddress, uint32 port, IPFuncPtr funcPtr); +void IPWriteFlush(IPSocket *socket); +uint32 IPWrite(IPSocket *socket, const uint8 *buf, uint32 length); +uint32 IPRead(IPSocket *socket, uint8 *buf, uint32 length); +void IPClose(IPSocket *socket); +#ifdef IPPRINTF +void IPPrintf(IPSocket *socket, char *message, int arg0, int arg1, int arg2, int arg3); +#else +void IPPrintf(IPSocket *socket, char *message, ...); +#endif +void IPResolve(char *name, IPFuncPtr resolvedFunc, void *arg); +uint32 IPAddressSelf(void); + +//http.c +#define HTML_LENGTH_CALLBACK -2 +#define HTML_LENGTH_LIST_END -1 +typedef struct PageEntry_s { + const char *name; + int length; + const char *page; +} PageEntry_t; +void HttpInit(const PageEntry_t *Pages, int UseFiles); + +//html.c +void HtmlInit(int UseFiles); + +//netutil.c +void FtpdInit(int UseFiles); +IPSocket *FtpTransfer(uint32 ip, char *user, char *passwd, + char *filename, uint8 *buf, int size, + int send, void (*callback)(uint8 *data, int size)); +void TftpdInit(void); +IPSocket *TftpTransfer(uint32 ip, char *filename, uint8 *buffer, int size, + void (*callback)(uint8 *data, int bytes)); +void ConsoleInit(void); +void *IPNameValue(const char *name, void *value); + +#endif //__TCPIP_H__ diff --git a/kernel/uart.c b/kernel/uart.c new file mode 100644 index 0000000..f813d7a --- /dev/null +++ b/kernel/uart.c @@ -0,0 +1,549 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Uart Driver + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/31/05 + * FILENAME: uart.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma Uart Driver + *--------------------------------------------------------------------*/ +#define NO_ELLIPSIS2 +#include "plasma.h" +#include "rtos.h" + +#ifndef NO_PACKETS +#define SUPPORT_DATA_PACKETS +#endif + +#define BUFFER_WRITE_SIZE 128 +#define BUFFER_READ_SIZE 128 +#define BUFFER_PRINTF_SIZE 1024 +#undef UartPrintf + +void UartPrintfCritical(const char *format, + int arg0, int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6, int arg7); + +typedef struct Buffer_s { + uint8 *data; + int size; + volatile int read, write; + volatile int pendingRead, pendingWrite; + OS_Semaphore_t *semaphoreRead, *semaphoreWrite; +} Buffer_t; + +static Buffer_t *WriteBuffer, *ReadBuffer; +static OS_Semaphore_t *SemaphoreUart; +static char PrintfString[BUFFER_PRINTF_SIZE]; //Used in UartPrintf + +#ifdef SUPPORT_DATA_PACKETS +//For packet processing [0xff lengthMSB lengthLSB checksum data] +static PacketGetFunc_t UartPacketGet; +static uint8 *PacketCurrent; +static uint32 UartPacketSize; +static uint32 UartPacketChecksum, Checksum; +static OS_MQueue_t *UartPacketMQueue; +static uint32 PacketBytes, PacketLength; +static uint32 UartPacketOutLength, UartPacketOutByte; +int CountOk, CountError; +#endif +static uint8 *UartPacketOut; + + +/******************************************/ +Buffer_t *BufferCreate(int size) +{ + Buffer_t *buffer; + buffer = (Buffer_t*)OS_HeapMalloc(NULL, sizeof(Buffer_t) + size); + if(buffer == NULL) + return NULL; + buffer->data = (uint8*)(buffer + 1); + buffer->read = 0; + buffer->write = 0; + buffer->size = size; + buffer->pendingRead = 0; + buffer->pendingWrite = 0; + buffer->semaphoreRead = OS_SemaphoreCreate("BufferRead", 0); + buffer->semaphoreWrite = OS_SemaphoreCreate("BufferWrite", 0); + return buffer; +} + + +void BufferWrite(Buffer_t *buffer, int value, int pend) +{ + int writeNext; + + writeNext = buffer->write + 1; + if(writeNext >= buffer->size) + writeNext = 0; + + //Check if room for value + if(writeNext == buffer->read) + { + if(pend == 0) + return; + ++buffer->pendingWrite; + OS_SemaphorePend(buffer->semaphoreWrite, OS_WAIT_FOREVER); + } + + buffer->data[buffer->write] = (uint8)value; + buffer->write = writeNext; + if(buffer->pendingRead) + { + --buffer->pendingRead; + OS_SemaphorePost(buffer->semaphoreRead); + } +} + + +int BufferRead(Buffer_t *buffer, int pend) +{ + int value; + + //Check if empty buffer + if(buffer->read == buffer->write) + { + if(pend == 0) + return 0; + ++buffer->pendingRead; + OS_SemaphorePend(buffer->semaphoreRead, OS_WAIT_FOREVER); + } + + value = buffer->data[buffer->read]; + if(++buffer->read >= buffer->size) + buffer->read = 0; + if(buffer->pendingWrite) + { + --buffer->pendingWrite; + OS_SemaphorePost(buffer->semaphoreWrite); + } + return value; +} + + +/******************************************/ +#ifdef SUPPORT_DATA_PACKETS +static void UartPacketRead(uint32 value) +{ + uint32 message[4]; + if(PacketBytes == 0 && value == 0xff) + { + ++PacketBytes; + } + else if(PacketBytes == 1) + { + ++PacketBytes; + PacketLength = value << 8; + } + else if(PacketBytes == 2) + { + ++PacketBytes; + PacketLength |= value; + if(PacketLength <= UartPacketSize) + { + if(PacketCurrent == NULL) + PacketCurrent = UartPacketGet(); + } + else + { + PacketBytes = 0; + } + } + else if(PacketBytes == 3) + { + ++PacketBytes; + UartPacketChecksum = value; + Checksum = 0; + } + else if(PacketBytes >= 4) + { + if(PacketCurrent) + PacketCurrent[PacketBytes - 4] = (uint8)value; + Checksum += value; + ++PacketBytes; + if(PacketBytes - 4 >= PacketLength) + { + if((uint8)Checksum == UartPacketChecksum) + { + //Notify thread that a packet has been received + ++CountOk; + message[0] = 0; + message[1] = (uint32)PacketCurrent; + message[2] = PacketLength; + if(PacketCurrent) + OS_MQueueSend(UartPacketMQueue, message); + PacketCurrent = NULL; + } + else + { + ++CountError; + //printf("E"); + } + PacketBytes = 0; + } + } +} + + +static int UartPacketWrite(void) +{ + int value=0, i; + uint32 message[4]; + if(UartPacketOut) + { + if(UartPacketOutByte == 0) + { + value = 0xff; + ++UartPacketOutByte; + } + else if(UartPacketOutByte == 1) + { + value = UartPacketOutLength >> 8; + ++UartPacketOutByte; + } + else if(UartPacketOutByte == 2) + { + value = (uint8)UartPacketOutLength; + ++UartPacketOutByte; + } + else if(UartPacketOutByte == 3) + { + value = 0; + for(i = 0; i < (int)UartPacketOutLength; ++i) + value += UartPacketOut[i]; + value = (uint8)value; + ++UartPacketOutByte; + } + else + { + value = UartPacketOut[UartPacketOutByte - 4]; + ++UartPacketOutByte; + if(UartPacketOutByte - 4 >= UartPacketOutLength) + { + //Notify thread that a packet has been sent + message[0] = 1; + message[1] = (uint32)UartPacketOut; + UartPacketOut = 0; + OS_MQueueSend(UartPacketMQueue, message); + } + } + } + return value; +} +#endif + + +static void UartInterrupt(void *arg) +{ + uint32 status, value, count=0; + (void)arg; + + status = OS_InterruptStatus(); + while(status & IRQ_UART_READ_AVAILABLE) + { + value = MemoryRead(UART_READ); +#ifdef SUPPORT_DATA_PACKETS + if(UartPacketGet && (value == 0xff || PacketBytes)) + UartPacketRead(value); + else +#endif + BufferWrite(ReadBuffer, value, 0); + status = OS_InterruptStatus(); + if(++count >= 16) + break; + } + while(status & IRQ_UART_WRITE_AVAILABLE) + { +#ifdef SUPPORT_DATA_PACKETS + if(UartPacketOut) + { + value = UartPacketWrite(); + MemoryWrite(UART_WRITE, value); + } else +#endif + if(WriteBuffer->read != WriteBuffer->write) + { + value = BufferRead(WriteBuffer, 0); + MemoryWrite(UART_WRITE, value); + } + else + { + OS_InterruptMaskClear(IRQ_UART_WRITE_AVAILABLE); + break; + } + status = OS_InterruptStatus(); + } +} + + +void UartInit(void) +{ + uint32 mask; + + SemaphoreUart = OS_SemaphoreCreate("Uart", 1); + WriteBuffer = BufferCreate(BUFFER_WRITE_SIZE); + ReadBuffer = BufferCreate(BUFFER_READ_SIZE); + + mask = IRQ_UART_READ_AVAILABLE | IRQ_UART_WRITE_AVAILABLE; + OS_InterruptRegister(mask, UartInterrupt); + OS_InterruptMaskSet(IRQ_UART_READ_AVAILABLE); +} + + +void UartWrite(int ch) +{ + BufferWrite(WriteBuffer, ch, 1); + OS_InterruptMaskSet(IRQ_UART_WRITE_AVAILABLE); +} + + +uint8 UartRead(void) +{ + return (uint8)BufferRead(ReadBuffer, 1); +} + + +void UartWriteData(uint8 *data, int length) +{ + OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); + while(length--) + UartWrite(*data++); + OS_SemaphorePost(SemaphoreUart); +} + + +void UartReadData(uint8 *data, int length) +{ + OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); + while(length--) + *data++ = UartRead(); + OS_SemaphorePost(SemaphoreUart); +} + + +void UartPrintf(const char *format, + int arg0, int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6, int arg7) +{ + uint8 *ptr; +#if 0 + //Check for string "!m#~" to mask print statement + static char moduleLevel[26]; + if(format[0] == '!' && format[3] == '~') + { + int level = format[2] - '5'; + if('a' <= format[1] && format[1] <= 'z') + { + if(level < moduleLevel[format[1] - 'a']) + return; + } + else if('A' <= format[1] && format[1] <= 'Z') + moduleLevel[format[1] - 'A'] = (char)level; + format += 4; + } +#endif + OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); + sprintf(PrintfString, format, arg0, arg1, arg2, arg3, + arg4, arg5, arg6, arg7); + ptr = (uint8*)PrintfString; + while(*ptr) + { + if(*ptr == '\n') + UartWrite('\r'); +#ifdef SUPPORT_DATA_PACKETS + if(*ptr == 0xff) + *ptr = '@'; +#endif + UartWrite(*ptr++); + } + OS_SemaphorePost(SemaphoreUart); +} + + +void UartPrintfPoll(const char *format, + int arg0, int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6, int arg7) +{ + uint8 *ptr; + uint32 state; + + if(SemaphoreUart) + OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); + sprintf(PrintfString, format, arg0, arg1, arg2, arg3, + arg4, arg5, arg6, arg7); + ptr = (uint8*)PrintfString; + while(*ptr) + { + while((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) == 0) + ; + state = OS_CriticalBegin(); + if((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) && + UartPacketOut == NULL) + { + MemoryWrite(UART_WRITE, *ptr++); + } + OS_CriticalEnd(state); + } + if(SemaphoreUart) + OS_SemaphorePost(SemaphoreUart); +} + + +void UartPrintfCritical(const char *format, + int arg0, int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6, int arg7) +{ + uint8 *ptr; + uint32 state; + + state = OS_CriticalBegin(); + sprintf(PrintfString, format, arg0, arg1, arg2, arg3, + arg4, arg5, arg6, arg7); + ptr = (uint8*)PrintfString; + while(*ptr) + { + while((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) == 0) + ; + MemoryWrite(UART_WRITE, *ptr++); +#ifdef SUPPORT_DATA_PACKETS + if(UartPacketOut && UartPacketOutByte - 4 < UartPacketOutLength) + { + ++UartPacketOutByte; + --ptr; + } +#endif + } + memset(PrintfString, 0, sizeof(PrintfString)); + OS_CriticalEnd(state); +} + + +void UartPrintfNull(void) +{ +} + + +void UartScanf(const char *format, + int arg0, int arg1, int arg2, int arg3, + int arg4, int arg5, int arg6, int arg7) +{ + int index = 0, ch; + OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); + for(;;) + { + ch = UartRead(); + if(ch != '\b' || index) + UartWrite(ch); + if(ch == '\n' || ch == '\r') + break; + else if(ch == '\b') + { + if(index) + { + UartWrite(' '); + UartWrite(ch); + --index; + } + } + else if(index < sizeof(PrintfString)) + PrintfString[index++] = (uint8)ch; + } + UartWrite('\n'); + PrintfString[index] = 0; + sscanf(PrintfString, format, arg0, arg1, arg2, arg3, + arg4, arg5, arg6, arg7); + OS_SemaphorePost(SemaphoreUart); +} + + +#ifdef SUPPORT_DATA_PACKETS +void UartPacketConfig(PacketGetFunc_t PacketGetFunc, + int PacketSize, + OS_MQueue_t *mQueue) +{ + UartPacketGet = PacketGetFunc; + UartPacketSize = PacketSize; + UartPacketMQueue = mQueue; +} + + +void UartPacketSend(uint8 *data, int bytes) +{ + UartPacketOutByte = 0; + UartPacketOutLength = bytes; + UartPacketOut = data; + OS_InterruptMaskSet(IRQ_UART_WRITE_AVAILABLE); +} +#else +void UartPacketConfig(PacketGetFunc_t PacketGetFunc, + int PacketSize, + OS_MQueue_t *mQueue) +{ (void)PacketGetFunc; (void)PacketSize; (void)mQueue; } + + +void UartPacketSend(uint8 *data, int bytes) +{ (void)data; (void)bytes; } +#endif + + +void Led(int mask, int value) +{ + mask &= 0xff; + MemoryWrite(GPIO0_CLEAR, mask); //clear + MemoryWrite(GPIO0_OUT, value & mask); //set LEDs +} + + +/******************************************/ +int puts(const char *string) +{ + uint8 *ptr; + OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); + ptr = (uint8*)string; + while(*ptr) + { + if(*ptr == '\n') + UartWrite('\r'); + UartWrite(*ptr++); + } + OS_SemaphorePost(SemaphoreUart); + return 0; +} + + +int getch(void) +{ + return BufferRead(ReadBuffer, 1); +} + + +int kbhit(void) +{ + return ReadBuffer->read != ReadBuffer->write; +} + + +/******************************************/ +#if 0 +int LogArray[100], LogIndex; +void LogWrite(int a) +{ + if(LogIndex < sizeof(LogArray)/4) + LogArray[LogIndex++] = a; +} + +void LogDump(void) +{ + int i; + for(i = 0; i < LogIndex; ++i) + { + if(LogArray[i] > 0xfff) + UartPrintfCritical("\n", 0,0,0,0,0,0,0,0); + UartPrintfCritical("0x%x ", LogArray[i], 0,0,0,0,0,0,0); + } + LogIndex = 0; +} +#endif + diff --git a/tools/bintohex.c b/tools/bintohex.c new file mode 100644 index 0000000..67bf1df --- /dev/null +++ b/tools/bintohex.c @@ -0,0 +1,64 @@ +/*bintohex by Steve Rhoads 5/29/02*/ +#include +#include +#include + +#define BUF_SIZE (1024*1024) + +int main(int argc, char *argv[]) +{ + FILE *file; + unsigned char *buf; + unsigned long size, mem_size = 1024 * 4, i, j, k, sum; + char filename[80]; + + if(argc < 2) + { + printf ("usage: bintohex infile\n"); + return -1; + } + file = fopen(argv[1], "rb"); + if(file == NULL) + { + printf("Can't open %s\n", argv[1]); + return -1; + } + + buf = (unsigned char *)malloc(BUF_SIZE); + memset(buf, 0, BUF_SIZE); + size = fread(buf, 1, BUF_SIZE, file); + mem_size = size; + if(size > mem_size) + { + printf("FILE TOO LARGE!!!!!!!!!!!\n"); + return -1; + } + fclose(file); + strcpy(filename, "codeX.hex"); + + for(i = 0; i < 4; ++i) + { + filename[4] = '0' + i; + file = fopen(filename, "wb"); + for(j = 0; i + j * 4 * 16 < mem_size; ++j) + { + k = j * 16; + fprintf(file, ":10%4.4x00", (int)k); + sum = 0x10 + (k >> 8) + (k & 0xff); + for(k = 0; k < 16; ++k) + { + fprintf(file, "%2.2x", buf[i + j * 4 * 16 + k * 4]); + sum += buf[i + j * 4 * 16 + k * 4]; + } + sum &= 0xff; + sum = 0x100 - sum; + sum &= 0xff; + fprintf(file, "%2.2x\n", (int)sum); + } + fprintf(file, ":00000001ff\n"); + fclose(file); + } + free(buf); + return 0; +} + diff --git a/tools/boot.asm b/tools/boot.asm new file mode 100644 index 0000000..9b412a9 --- /dev/null +++ b/tools/boot.asm @@ -0,0 +1,239 @@ +################################################################## +# TITLE: Boot Up Code +# AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +# DATE CREATED: 1/12/02 +# FILENAME: boot.asm +# PROJECT: Plasma CPU core +# COPYRIGHT: Software placed into the public domain by the author. +# Software 'as is' without warranty. Author liable for nothing. +# DESCRIPTION: +# Initializes the stack pointer and jumps to main(). +################################################################## + #Reserve 512 bytes for stack + .comm InitStack, 512 + + .text + .align 2 + .global entry + .ent entry +entry: + .set noreorder + + #These four instructions should be the first instructions. + #convert.exe previously initialized $gp, .sbss_start, .bss_end, $sp + la $gp, _gp #initialize global pointer + la $5, __bss_start #$5 = .sbss_start + la $4, _end #$2 = .bss_end + la $sp, InitStack+488 #initialize stack pointer + +$BSS_CLEAR: + sw $0, 0($5) + slt $3, $5, $4 + bnez $3, $BSS_CLEAR + addiu $5, $5, 4 + + jal main + nop +$L1: + j $L1 + + .end entry + + +################################################### + #address 0x3c + .global interrupt_service_routine + .ent interrupt_service_routine +interrupt_service_routine: + .set noreorder + .set noat + + #Registers $26 and $27 are reserved for the OS + #Save all temporary registers + #Slots 0($29) through 12($29) reserved for saving a0-a3 + addi $29, $29, -104 #adjust sp + sw $1, 16($29) #at + sw $2, 20($29) #v0 + sw $3, 24($29) #v1 + sw $4, 28($29) #a0 + sw $5, 32($29) #a1 + sw $6, 36($29) #a2 + sw $7, 40($29) #a3 + sw $8, 44($29) #t0 + sw $9, 48($29) #t1 + sw $10, 52($29) #t2 + sw $11, 56($29) #t3 + sw $12, 60($29) #t4 + sw $13, 64($29) #t5 + sw $14, 68($29) #t6 + sw $15, 72($29) #t7 + sw $24, 76($29) #t8 + sw $25, 80($29) #t9 + sw $31, 84($29) #lr + mfc0 $26, $14 #C0_EPC=14 (Exception PC) + addi $26, $26, -4 #Backup one opcode + sw $26, 88($29) #pc + mfhi $27 + sw $27, 92($29) #hi + mflo $27 + sw $27, 96($29) #lo + + lui $6, 0x2000 + lw $4, 0x20($6) #IRQ_STATUS + lw $6, 0x10($6) #IRQ_MASK + and $4, $4, $6 + jal OS_InterruptServiceRoutine + addi $5, $29, 0 + + #Restore all temporary registers + lw $1, 16($29) #at + lw $2, 20($29) #v0 + lw $3, 24($29) #v1 + lw $4, 28($29) #a0 + lw $5, 32($29) #a1 + lw $6, 36($29) #a2 + lw $7, 40($29) #a3 + lw $8, 44($29) #t0 + lw $9, 48($29) #t1 + lw $10, 52($29) #t2 + lw $11, 56($29) #t3 + lw $12, 60($29) #t4 + lw $13, 64($29) #t5 + lw $14, 68($29) #t6 + lw $15, 72($29) #t7 + lw $24, 76($29) #t8 + lw $25, 80($29) #t9 + lw $31, 84($29) #lr + lw $26, 88($29) #pc + lw $27, 92($29) #hi + mthi $27 + lw $27, 96($29) #lo + mtlo $27 + addi $29, $29, 104 #adjust sp + +isr_return: + ori $27, $0, 0x1 #re-enable interrupts + jr $26 + mtc0 $27, $12 #STATUS=1; enable interrupts + + .end interrupt_service_routine + .set at + + +################################################### + .global OS_AsmInterruptEnable + .ent OS_AsmInterruptEnable +OS_AsmInterruptEnable: + .set noreorder + mfc0 $2, $12 + jr $31 + mtc0 $4, $12 #STATUS=1; enable interrupts + #nop + .set reorder + .end OS_AsmInterruptEnable + + +################################################### + .global OS_AsmInterruptInit + .ent OS_AsmInterruptInit +OS_AsmInterruptInit: + .set noreorder + #Patch interrupt vector to 0x1000003c + la $5, OS_AsmPatchValue + lw $6, 0($5) + sw $6, 0x3c($0) + lw $6, 4($5) + sw $6, 0x40($0) + lw $6, 8($5) + sw $6, 0x44($0) + lw $6, 12($5) + jr $31 + sw $6, 0x48($0) + +OS_AsmPatchValue: + #Registers $26 and $27 are reserved for the OS + #Code to place at address 0x3c + lui $26, 0x1000 + ori $26, $26, 0x3c + jr $26 + nop + + .set reorder + .end OS_AsmInterruptInit + + +################################################### + .global setjmp + .ent setjmp +setjmp: + .set noreorder + sw $16, 0($4) #s0 + sw $17, 4($4) #s1 + sw $18, 8($4) #s2 + sw $19, 12($4) #s3 + sw $20, 16($4) #s4 + sw $21, 20($4) #s5 + sw $22, 24($4) #s6 + sw $23, 28($4) #s7 + sw $30, 32($4) #s8 + sw $28, 36($4) #gp + sw $29, 40($4) #sp + sw $31, 44($4) #lr + jr $31 + ori $2, $0, 0 + + .set reorder + .end setjmp + + +################################################### + .global longjmp + .ent longjmp +longjmp: + .set noreorder + lw $16, 0($4) #s0 + lw $17, 4($4) #s1 + lw $18, 8($4) #s2 + lw $19, 12($4) #s3 + lw $20, 16($4) #s4 + lw $21, 20($4) #s5 + lw $22, 24($4) #s6 + lw $23, 28($4) #s7 + lw $30, 32($4) #s8 + lw $28, 36($4) #gp + lw $29, 40($4) #sp + lw $31, 44($4) #lr + jr $31 + ori $2, $5, 0 + + .set reorder + .end longjmp + + +################################################### + .global OS_AsmMult + .ent OS_AsmMult +OS_AsmMult: + .set noreorder + multu $4, $5 + mflo $2 + mfhi $4 + jr $31 + sw $4, 0($6) + + .set reorder + .end OS_AsmMult + + +################################################### + .global OS_Syscall + .ent OS_Syscall +OS_Syscall: + .set noreorder + syscall 0 + jr $31 + nop + .set reorder + .end OS_Syscall + + diff --git a/tools/bootldr.c b/tools/bootldr.c new file mode 100644 index 0000000..40b7646 --- /dev/null +++ b/tools/bootldr.c @@ -0,0 +1,265 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Bootloader + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/17/05 + * FILENAME: bootldr.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma bootloader. + *--------------------------------------------------------------------*/ +#include "plasma.h" + +#define MemoryRead(A) (*(volatile unsigned long*)(A)) +#define MemoryWrite(A,V) *(volatile unsigned long*)(A)=(V) + +extern int putchar(int ch); +extern int puts(const char *string); +extern int getch(void); +extern int kbhit(void); +extern int DdrInit(void); + +typedef void (*FuncPtr)(void); +typedef unsigned long uint32; +typedef unsigned short uint16; + + +void FlashRead(uint16 *dst, uint32 byteOffset, int bytes) +{ + volatile uint32 *ptr=(uint32*)(FLASH_BASE + (byteOffset << 1)); + *ptr = 0xff; //read mode + while(bytes > 0) + { + *dst++ = (uint16)*ptr++; + bytes -= 2; + } +} + + +void FlashWrite(uint16 *src, uint32 byteOffset, int bytes) +{ + volatile uint32 *ptr=(uint32*)(FLASH_BASE + (byteOffset << 1)); + while(bytes > 0) + { + *ptr = 0x40; //write mode + *ptr++ = *src++; //write data + while((*ptr & 0x80) == 0) //check status + ; + bytes -= 2; + } +} + + +void FlashErase(uint32 byteOffset) +{ + volatile uint32 *ptr=(uint32*)(FLASH_BASE + (byteOffset << 1)); + *ptr = 0x20; //erase block + *ptr = 0xd0; //confirm + while((*ptr & 0x80) == 0) //check status + ; +} + + +char *xtoa(unsigned long num) +{ + static char buf[12]; + int i, digit; + buf[8] = 0; + for (i = 7; i >= 0; --i) + { + digit = num & 0xf; + buf[i] = digit + (digit < 10 ? '0' : 'A' - 10); + num >>= 4; + } + return buf; +} + + +unsigned long getnum(void) +{ + int i; + unsigned long ch, ch2, value=0; + for(i = 0; i < 16; ) + { + ch = ch2 = getch(); + if(ch == '\n' || ch == '\r') + break; + if('0' <= ch && ch <= '9') + ch -= '0'; + else if('A' <= ch && ch <= 'Z') + ch = ch - 'A' + 10; + else if('a' <= ch && ch <= 'z') + ch = ch - 'a' + 10; + else if(ch == 8) + { + if(i > 0) + { + --i; + putchar(ch); + putchar(' '); + putchar(ch); + } + value >>= 4; + continue; + } + putchar(ch2); + value = (value << 4) + ch; + ++i; + } + putchar('\r'); + putchar('\n'); + return value; +} + + +int main(void) +{ + int i, j, ch; + unsigned long address, value, count; + FuncPtr funcPtr; + unsigned char *ptr1; + + DdrInit(); //Harmless if SDRAM instead of DDR + + puts("\nGreetings from the bootloader "); + puts(__DATE__); + puts(" "); + puts(__TIME__); + puts(":\n"); + MemoryWrite(FLASH_BASE, 0xff); //read mode + if((MemoryRead(GPIOA_IN) & 1) && (MemoryRead(FLASH_BASE) & 0xffff) == 0x3c1c) + { + puts("Boot from flash\n"); + FlashRead((uint16*)RAM_EXTERNAL_BASE, 0, 1024*128); + funcPtr = (FuncPtr)RAM_EXTERNAL_BASE; + funcPtr(); + } + for(;;) + { + puts("\nWaiting for binary image linked at 0x10000000\n"); + puts("Other Menu Options:\n"); + puts("1. Memory read word\n"); + puts("2. Memory write word\n"); + puts("3. Memory read byte\n"); + puts("4. Memory write byte\n"); + puts("5. Jump to address\n"); + puts("6. Raw memory read\n"); + puts("7. Raw memory write\n"); + puts("8. Checksum\n"); + puts("9. Dump\n"); + puts("F. Copy 128KB from DDR to flash\n"); + puts("> "); + ch = getch(); + address = 0; + if('0' <= ch && ch <= '9') + { + putchar(ch); + puts("\nAddress in hex> "); + address = getnum(); + puts("Address = "); + puts(xtoa(address)); + puts("\n"); + } + switch(ch) + { + case '1': + value = MemoryRead(address); + puts(xtoa(value)); + puts("\n"); + break; + case '2': + puts("\nValue in hex> "); + value = getnum(); + puts(xtoa(value)); + MemoryWrite(address, value); + break; + case '3': + value = *(unsigned char*)address; + puts(xtoa(value)); + puts("\n"); + break; + case '4': + puts("\nValue in hex> "); + value = getnum(); + puts(xtoa(value)); + *(unsigned char*)address = value; + break; + case '5': + funcPtr = (FuncPtr)address; + funcPtr(); + break; + case '6': + puts("\nCount in hex> "); + count = getnum(); + for(i = 0; i < count; ++i) + { + ch = *(unsigned char*)(address + i); + putchar(ch); + } + break; + case '7': + puts("\nCount in hex> "); + count = getnum(); + for(i = 0; i < count; ++i) + { + ch = getch(); + *(unsigned char*)(address+i) = ch; + } + break; + case '8': + puts("\nCount in hex> "); + count = getnum(); + value = 0; + for(i = 0; i < count; ++i) + { + value += *(unsigned char*)(address+i); + } + puts(xtoa(value)); + putchar('\n'); + break; + case '9': + puts("\nCount in hex> "); + count = getnum(); + value = 0; + for(i = 0; i < count; i += 4) + { + if((i & 15) == 0) + puts("\r\n"); + value = *(unsigned long*)(address+i); + puts(xtoa(value)); + putchar(' '); + } + puts("\r\n"); + break; + case 'F': + puts("\nConfirm with 12345678> "); + value = getnum(); + if(value == 0x12345678) + { + FlashErase(0); + FlashWrite((uint16*)RAM_EXTERNAL_BASE, 0, 1024*128); + } + break; + case 0x3c: //raw test.bin file + ptr1 = (unsigned char*)0x10000000; + for(i = 0; i < 1024*1024; ++i) + { + ptr1[i] = (unsigned char)ch; + for(j = 0; j < 10000; ++j) + { + if(kbhit()) + break; + } + if(j >= 10000) + break; //assume end of file + ch = getch(); + } + funcPtr = (FuncPtr)0x10000000; + funcPtr(); + break; + } + } + return 0; +} + diff --git a/tools/convert.c b/tools/convert.c new file mode 100644 index 0000000..f87e485 --- /dev/null +++ b/tools/convert.c @@ -0,0 +1,258 @@ +//convert.c by Steve Rhoads 4/26/01 +//Now uses the ELF format (get gccmips_elf.zip) +//set $gp and zero .sbss and .bss +//Reads test.axf and creates code.txt +#include +#include +#include + +#define BUF_SIZE (1024*1024*4) +/*Assumes running on PC little endian*/ +#ifndef USE_BIG_ENDIAN +#define ntohl(A) (((A)>>24)|(((A)&0x00ff0000)>>8)|(((A)&0xff00)<<8)|((A)<<24)) +#define ntohs(A) (uint16)((((A)&0xff00)>>8)|((A)<<8)) +#else +#define ntohl(A) A +#define ntohs(A) A +#endif + +#define EI_NIDENT 16 +#define SHT_PROGBITS 1 +#define SHT_STRTAB 3 +#define SHT_NOBITS 8 + +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef struct +{ + uint8 e_ident[EI_NIDENT]; + uint16 e_e_type; + uint16 e_machine; + uint32 e_version; + uint32 e_entry; + uint32 e_phoff; + uint32 e_shoff; + uint32 e_flags; + uint16 e_ehsize; + uint16 e_phentsize; + uint16 e_phnum; + uint16 e_shentsize; + uint16 e_shnum; + uint16 e_shstrndx; +} ElfHeader; + +typedef struct +{ + uint32 p_type; + uint32 p_offset; + uint32 p_vaddr; + uint32 p_paddr; + uint32 p_filesz; + uint32 p_memsz; + uint32 p_flags; + uint32 p_align; +} Elf32_Phdr; + +typedef struct +{ + uint32 sh_name; + uint32 sh_type; + uint32 sh_flags; + uint32 sh_addr; + uint32 sh_offset; + uint32 sh_size; + uint32 sh_link; + uint32 sh_info; + uint32 sh_addralign; + uint32 sh_entsize; +} Elf32_Shdr; + +typedef struct +{ + uint32 ri_gprmask; + uint32 ri_cprmask[4]; + uint32 ri_gp_value; +} ELF_RegInfo; + +#define PT_MIPS_REGINFO 0x70000000 +#define SHT_MIPS_REGINFO 0x70000006 + +void set_low(uint8 *ptr, uint32 address, uint32 value) +{ + uint32 opcode; + opcode = *(uint32 *)(ptr + address); + opcode = ntohl(opcode); + opcode = (opcode & 0xffff0000) | (value & 0xffff); + opcode = ntohl(opcode); + *(uint32 *)(ptr + address) = opcode; +} + +int main(int argc, char *argv[]) +{ + FILE *infile, *outfile, *txtfile; + uint8 *buf, *code; + long size, stack_pointer; + uint32 length, d, i, gp_ptr = 0, gp_ptr_backup = 0; + uint32 bss_start = 0, bss_end = 0; + + ElfHeader *elfHeader; + Elf32_Phdr *elfProgram; + ELF_RegInfo *elfRegInfo; + Elf32_Shdr *elfSection; + (void)argc; + (void)argv; + (void)stack_pointer; + + printf("test.axf -> code.txt & test.bin\n"); + infile = fopen("test.axf", "rb"); + if(infile == NULL) + { + printf("Can't open test.axf"); + return 0; + } + buf = (uint8*)malloc(BUF_SIZE); + size = (int)fread(buf, 1, BUF_SIZE, infile); + fclose(infile); + code = (uint8*)malloc(BUF_SIZE); + memset(code, 0, BUF_SIZE); + + elfHeader = (ElfHeader *)buf; + if(strncmp((char*)elfHeader->e_ident + 1, "ELF", 3)) + { + printf("Error: Not an ELF file!\n"); + printf("Use the gccmips_elf.zip from opencores/projects/plasma!\n"); + return -1; + } + + elfHeader->e_entry = ntohl(elfHeader->e_entry); + elfHeader->e_phoff = ntohl(elfHeader->e_phoff); + elfHeader->e_shoff = ntohl(elfHeader->e_shoff); + elfHeader->e_flags = ntohl(elfHeader->e_flags); + elfHeader->e_phentsize = ntohs(elfHeader->e_phentsize); + elfHeader->e_phnum = ntohs(elfHeader->e_phnum); + elfHeader->e_shentsize = ntohs(elfHeader->e_shentsize); + elfHeader->e_shnum = ntohs(elfHeader->e_shnum); + printf("Entry=0x%x ", elfHeader->e_entry); + length = 0; + + for(i = 0; i < elfHeader->e_phnum; ++i) + { + elfProgram = (Elf32_Phdr *)(buf + elfHeader->e_phoff + + elfHeader->e_phentsize * i); + elfProgram->p_type = ntohl(elfProgram->p_type); + elfProgram->p_offset = ntohl(elfProgram->p_offset); + elfProgram->p_vaddr = ntohl(elfProgram->p_vaddr); + elfProgram->p_filesz = ntohl(elfProgram->p_filesz); + elfProgram->p_memsz = ntohl(elfProgram->p_memsz); + elfProgram->p_flags = ntohl(elfProgram->p_flags); + + elfProgram->p_vaddr -= elfHeader->e_entry; + + if(elfProgram->p_type == PT_MIPS_REGINFO) + { + elfRegInfo = (ELF_RegInfo*)(buf + elfProgram->p_offset); + gp_ptr = ntohl(elfRegInfo->ri_gp_value); + } + if(elfProgram->p_vaddr < BUF_SIZE) + { + //printf("[0x%x,0x%x,0x%x,0x%x,0x%x]\n", elfProgram->p_vaddr, + // elfProgram->p_offset, elfProgram->p_filesz, elfProgram->p_memsz, + // elfProgram->p_flags); + memcpy(code + elfProgram->p_vaddr, buf + elfProgram->p_offset, + elfProgram->p_filesz); + length = elfProgram->p_vaddr + elfProgram->p_filesz; + //printf("length = %d 0x%x\n", length, length); + } + } + + for(i = 0; i < elfHeader->e_shnum; ++i) + { + elfSection = (Elf32_Shdr *)(buf + elfHeader->e_shoff + + elfHeader->e_shentsize * i); + elfSection->sh_name = ntohl(elfSection->sh_name); + elfSection->sh_type = ntohl(elfSection->sh_type); + elfSection->sh_addr = ntohl(elfSection->sh_addr); + elfSection->sh_offset = ntohl(elfSection->sh_offset); + elfSection->sh_size = ntohl(elfSection->sh_size); + + if(elfSection->sh_type == SHT_MIPS_REGINFO) + { + elfRegInfo = (ELF_RegInfo*)(buf + elfSection->sh_offset); + gp_ptr = ntohl(elfRegInfo->ri_gp_value); + } + if(elfSection->sh_type == SHT_PROGBITS) + { + //printf("elfSection->sh_addr=0x%x\n", elfSection->sh_addr); + if(elfSection->sh_addr > gp_ptr_backup) + gp_ptr_backup = elfSection->sh_addr; + } + if(elfSection->sh_type == SHT_NOBITS) + { + if(bss_start == 0) + { + bss_start = elfSection->sh_addr; + } + bss_end = elfSection->sh_addr + elfSection->sh_size; + } + } + + if(length > bss_start - elfHeader->e_entry) + { + length = bss_start - elfHeader->e_entry; + } + if(bss_start == length) + { + bss_start = length; + bss_end = length + 4; + } + if(gp_ptr == 0) + gp_ptr = gp_ptr_backup + 0x7ff0; + +#if 0 + /*Initialize the $gp register for sdata and sbss */ + printf("gp_ptr=0x%x ", gp_ptr); + /*modify the first opcodes in boot.asm */ + /*modify the lui opcode */ + set_low(code, 0, gp_ptr >> 16); + /*modify the ori opcode */ + set_low(code, 4, gp_ptr & 0xffff); + + /*Clear .sbss and .bss */ + printf("sbss=0x%x bss_end=0x%x\nlength=0x%x ", bss_start, bss_end, length); + set_low(code, 8, bss_start >> 16); + set_low(code, 12, bss_start & 0xffff); + set_low(code, 16, bss_end >> 16); + set_low(code, 20, bss_end & 0xffff); + + /*Set stack pointer */ + if(elfHeader->e_entry < 0x10000000) + stack_pointer = bss_end + 512; + else + stack_pointer = bss_end + 1024 * 4; + stack_pointer &= ~7; + printf("SP=0x%x\n", stack_pointer); + set_low(code, 24, stack_pointer >> 16); + set_low(code, 28, stack_pointer & 0xffff); +#endif + + /*write out test.bin */ + outfile = fopen("test.bin", "wb"); + fwrite(code, length, 1, outfile); + fclose(outfile); + + /*write out code.txt */ + txtfile = fopen("code.txt", "w"); + for(i = 0; i <= length; i += 4) + { + d = ntohl(*(uint32 *)(code + i)); + fprintf(txtfile, "%8.8x\n", d); + } + fclose(txtfile); + free(buf); + printf("length=%d=0x%x\n", length, length); + + return 0; +} + diff --git a/tools/count.c b/tools/count.c new file mode 100644 index 0000000..b0225a3 --- /dev/null +++ b/tools/count.c @@ -0,0 +1,142 @@ +/*count.c*/ +int putchar(int value); +int puts(const char *string); + +char *name[] = { + "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", + "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen", + "", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", + "eighty", "ninety" +}; + +char *xtoa(unsigned long num) +{ + static char buf[12]; + int i, digit; + buf[8] = 0; + for (i = 7; i >= 0; --i) + { + digit = num & 0xf; + buf[i] = digit + (digit < 10 ? '0' : 'A' - 10); + num >>= 4; + } + return buf; +} + +char *itoa10(unsigned long num) +{ + static char buf[12]; + int i; + buf[10] = 0; + for (i = 9; i >= 0; --i) + { + buf[i] = (char)((num % 10) + '0'); + num /= 10; + } + return buf; +} + +void number_text(unsigned long number) +{ + int digit; + puts(itoa10(number)); + puts(": "); + if(number >= 1000000000) + { + digit = number / 1000000000; + puts(name[digit]); + puts(" billion "); + number %= 1000000000; + } + if(number >= 100000000) + { + digit = number / 100000000; + puts(name[digit]); + puts(" hundred "); + number %= 100000000; + if(number < 1000000) + { + puts("million "); + } + } + if(number >= 20000000) + { + digit = number / 10000000; + puts(name[digit + 20]); + putchar(' '); + number %= 10000000; + if(number < 1000000) + { + puts("million "); + } + } + if(number >= 1000000) + { + digit = number / 1000000; + puts(name[digit]); + puts(" million "); + number %= 1000000; + } + if(number >= 100000) + { + digit = number / 100000; + puts(name[digit]); + puts(" hundred "); + number %= 100000; + if(number < 1000) + { + puts("thousand "); + } + } + if(number >= 20000) + { + digit = number / 10000; + puts(name[digit + 20]); + putchar(' '); + number %= 10000; + if(number < 1000) + { + puts("thousand "); + } + } + if(number >= 1000) + { + digit = number / 1000; + puts(name[digit]); + puts(" thousand "); + number %= 1000; + } + if(number >= 100) + { + digit = number / 100; + puts(name[digit]); + puts(" hundred "); + number %= 100; + } + if(number >= 20) + { + digit = number / 10; + puts(name[digit + 20]); + putchar(' '); + number %= 10; + } + puts(name[number]); + putchar ('\r'); + putchar ('\n'); +} + + +int main() +{ + unsigned long number, i=0; + + number = 3; + for(i = 0;; ++i) + { + number_text(number); + number *= 3; + //++number; + } +} + diff --git a/tools/cpu.gif b/tools/cpu.gif new file mode 100644 index 0000000000000000000000000000000000000000..d21dfb6b01a1f31dae1dae408aae1fe0a4033530 GIT binary patch literal 10775 zcmeI0bz2h-pm0?LrBy&0{ZZ20-Q8USX-24YgM@T9Y=Crk$7n{!fH68pcT0`?-p}#g z^AXPToPUnIqMU%BIp>=XZ|+|GFE9Vc{~7rI)d0)?7Vy6*2~sL&;RGLhTm6w{ewQhwCzDWJ` zG4_anF4KzJE5uYTp?Ki^Kngh57H@7fMY(%Y-9yvDSb=k zpo+>a_IF-_m%qQq}yKwz7yL2H#!=LJ+%1lmwF#r>$#)WdR2=@FhAHUi55M(A@bde zmzT5&qEn!URTr%k4aVXkcU4I->kJqtW1H$7t zxr_WE+|qV*dSBX^UNN)p4q*{lXu;PL8S)Ut=h_<^qI-rTj(q%X@zP91wTqq&0jb?@Q>QPLo@>%$U(mreHX=F&M+Z(AW& zgGXLyg==>o46053V^CcrSiOqCXk6me2!F5>@sr@dm9;p^32(z1Ee{H664<%g+I zZY@q_47Y-h4ZO8X_BFbFq=6|2(7Dv7&CgQNH83c=5gSh~c}w*^y+q>gKvE*C z4Ec6hUzxoAI5f0y7~fw}upc%cU%H6P%dV}m_xdW0*CL0*u(kbHUnOWOgkDfGVzP^l z38WxwB<$@n&L{^>>qNczj@mWsVWq5BPnKF}K#fobpj;ANXz6;D7L{!1YmB+y8q4qk zWxa)X7;Xw_sK*q>$jIg_KG5w;(J784`x9EK&e>7z?8u*`uoq@t9iS_y~t2judO$y#m{pic1f#}=$!v1UA zPVOTrl@7d%ncX(=>xV{o-s7&oGO3h9z(uyM&YtMmJ)gHtPVT$sC5gMZX|s=)cJv|E zH?P{q4;8uo*>onJdwdwp_;{A0cxT$pc*z;toKbu+eDL)7thE|`X@)bQ{{T>j!;i1a zu9n!8*~w=8U2g`y16JpVl$xBRnnDb4voL0aR8OyNEaF#f9X@u{snRgi@;_@BYG2O$ z4e$sQxKa?9A@MBky2Y9(cPergPF!2#Y?b^bYQWXLqAz^M>I!w(3^RtU(DPTHyc4LB zdg#1s{?*k0Ir9xam`CMY>7$`e)FB-kC7jzr`c*nU-^dG2pv?{c#c4*?R0tH~w6&vP zbih3<3gm-LU0X+$jyvVky84CF%u2Qk$CrnlVI_esMAdP!aOW=7+H_B5hij5?$37ix z>nM!(+J$K)TmH^_hQG_rqvLuTEZRJ%?Brgk|FEh1C4u&j=xNCnQ65=d?NJGQ`ge$VgKzVDtVE!jWgCH+tM zZ(VC70}E1}g|vfb5kVLH!OSGVqbP~0`yO7zsuo_VnR~pF|AO?>y!_?eP$RS9q8Z^(8$ROU zh?;M1jy7Sv9>F%@VSKjX;S1jbhe@)x0!$)YROZ91i9PnwWJ2T(voj2GOSvdoJ>(Rk zTAamlInWZL^$)PRV1Y_uo#u4q<&NF-`n|0Xz9tYgNy2@w zFL|^dtn@E#V?l9OK1Td5?8l%Uh({^dz@f_^=BYKILctlcE#h{b9sNM|-Yzh4IDwNo z{>mUK(;$9DmYuMT6}QdwG$W#DhXMIMQnDoW3!}_`kqI^SQQL<8-Tcnl*M$`Y9}lVzHzsbsZ3qK6^g2dOK1 zjyET*cqW^bIB}K4t7ay`Z&P&+!YvGwDen!ZA{=!|QsmzG45cO+FUI@=MoUEmxEZE* z(5HGUrs$5OlN*Krfa1rxaoWH*mXR=j!N5SE8`E%#6EL<-#>-0}W1S&Im^uUO9qJ&+ z&`*?}Ka!e58WGl-HH(p!NSYR0>|H#P2ve}CjO1>~1XUems1}17fSFBY=^7=V0ma`j z@)-q@`t`t!7}Ahp65tIqatagF7YQyT!0A?x9zzXq*+Odx$V}u zr$C!GMt>m~nc>B9M?l>ohDk8ltS)xMkF!R{j z3oZ|GDMl^jlyVfyl)VTT813_R<_p!@mDsVsoMia`kD|4tqBi~@fW6>%tYU4FqW*tb zg!aX?^17N4g`$J@{2{s0_j{vr5}@xK<^V<%ga9s zm2{4B4Gy{Y*c;komR3YnS=d*S=ztFoBVH@{9A$l;v!`4)avD>T-nOqE$f}4IDt2rM zPh6@lajof7D*uO7{*>j3D)+g;^8B)0nbMwQ#ix43i2urn58D^K zlvRgYUSUo`K`9)ZCspxIx%xo}RZs0uyN~78H5z4jS4VtQF92%b=%`z9t9NH&=8Mi0 zGOlImsOlK4EBnT7PQ;eznlIH+Sn^PuT%LN9P9x?JFNCha7nQ0JN-i|o@cFS(mc0Iv ztU)QgGVq-`k9`5fPNE7^8PP-K;$nj$bIdDrMHfOHA;UUWPz}3qvo&_}_weQ%pI;8- zis$;3n%FI&%*~bU^=z(9#Ckd`O(lSimQA4sY2n(p6`3~5?y((ea$0Q@p+#|zP4dfa z{6{T;4lQ)PbV;BbN%G>#jy7;bYgsf!-DAbij(lz3xS9^q3C(ZyN(PXloXAIcPlXO8 z(wK^lhBo2W3^G@y$F?xka)_2&`vkL#3wcdKUB@&q*F34@Uqmr5>UWDnV{dfhtWkw# zeknOz3GINl#x3D4I4ZADJru!$iI$rX{cQvLmswcBjaHjMrc6Z=#5lT(zq};=vF&-O z>!pGdsoef_mt+#HE}E&x`X}^ENaBpFk8;ZpJ*1?V*%>RQ1)Cy1%{X@a5F~4u`J1_C zQ>n+0T$W+H*?zP~n8k#HqCZ`sna8hF8{W)#-1EM&h_w^K)Hz@_6Ngz*_F9M$`%m{( zN3S8esD9=Ea;_A2ko=0bbCsY@i=rLx==WY(+nh4Ak*>+PB7BCdUB`w7OUGL$s9b8i zY;X+91A_LKLs88~%@&2K{-Ej@VMr4;RD-4Wz<4-*(cJWC*c{pMGX`2f);wg<{VyX` z$8T`_sLkdbJAv$=T8F9EO8Zx1>r(7|;>cmo@)&Jok`P4+*^xWuiYA%k=ns`v1eQTG z%Mf(?r>I|B&zQI2gF?QHSvbzHu@S_2X>^>zq;I9yu&FrX==%`3P-P{8TIDk-$xt=R zgr@8SJ}pIos|;SuctGKJ%J`TSf7k}agbe?L!gz^}uxXoPg3;4RvLkeAe(dAb*rv!7 zd&}TAm9gn%vv;bD;k2Xeo#TNjja?K|A64rzjbT&Fuvn4bZ&;^dcgA6$A#U(6?ehR( zReQ4`YUnGZi(z7_EM~NC21YW$?e{c&A~MZ>68bH6gvkfS8aqu_1>=OwCON`nj$v^f zFp`SdfTvm0(H3gfImN2ED6sviAAHc4xg%zlbalLqbU+!mK<%Ws0eg!=L)ol;BoE^J~jw4?FXMl*4G4y;4zgKNuH8{pYw(W&lnIe3sT~tXa#E z;TX~1B^2|(s)g!`0P)O)PsVdAnCiUP@VM9o?NtP3?4l!XR^G`Rqwy^Ldsz8%ElJj5 z!Sh1TIHHhs7|6XCz`E2>)t%^%0IM#$0EBS>)8NX+ws+(ej!P($kwKHD64rh#6ssmt zQ5;Tc@6wDc^TbNOKXhs}__Ozdv|)?aqjSFs!=Hm$k(1SUiWv*al@Qjo3;8xR3Vzd$ z)#=q0mleqAa&B2HE7HFo**UqGy%zR7d+a~aeX^c1v4P7rx$nD%9=H56e_7Ihc@~hi z8H<<{UAt9c!+1vQJ|d!hXG5Llqfgd)oR<6ix2$lN@Z&bQ#I|Xxx9|csK@(dynA;t( zTWQbR8V=h*tn05=wj~&9i_j6(t21P5%bh2iO{?o?7MrP6i+ZQaQd9~3xEl%CJHKUj zW>2;yOt)G5D|OelWO5MYb%-*jNvn6=1UNfvsE+H=ZGp9Ai^ zGb+U8#Ci$pDC+cZb>z@eZGRH)XyXJ4Q9IFGf%dMg!tq8;<90=|Pnz(m)7cKEtGiZK zs~W0L0Bd_j5M=(^(ZJ-zt&hjW~>CW#@eZbBs)y_mU`FF9CMYS_<*XDN4X{Ybe z8s0ue*M{`u*`p|QRc+y}dSjDn9sA`V?ev`F?1HfCbcqzTeUfwWrRMCidb<;F_7b;; zM4fz@SUP4o9;-gWGCt-DJVxv0Ko7j+Qs1Q&FM63c-()_Kz`vmRa&(M$&e?t9sd7~i zb~?ca`GvQT9B`%7{YwG=ygLyt=x}I|yG?&~BiX&3H+gA>KV9+2&9;8caaK9tZ59(} z$6OO>QM~K9zDwtgbYI_xQq@kBXZJ*@I)ZDK8E^vYqiLIF8`$VrHUx`zS8k5R=o>6 zH(wNZKF*f--<`+$^BRlUqaEgaJ-#&(|7uzMv6WnXer1}Y?AiCsZtBb3@pY6??!ylL zhu3fMXc<2A^n_qwV<<%Y+LVsKc+C@I0JD&dA||$(Gf1$M|MOKgj@IyUQ$Cqa)5Bzh zi>^O{z#8gjNMJLXM(lbxAXsN3{g+%6bq!2Ls>O(#QS&a%0f$SdGo`>v?qxHjS~Xh( z<@KeCndW&yv<5dwM5SWe4|LGHlU{@7cG^jK{i$)5!*ac7)b0K>$PN7t?9gy-(BX5z zrZ;Y2x80raF-+Ebq11ZZv*-cNbZx1Tk4mEpA-1H@BzD%kMm=G+J~|uGSH@rj%W3FKaVD#gV9JcJcjv?O(kM7%cJPuVx)M zBw8r^Y9-JXli4M4{`13=JRVT47RS^yRu{#?)ZvtdDw$mL;gL4Rb3NfTsMyLmmK2{U<64Z|t{|?n0V|AcNQY6go zOj2Pe%TH8dgI{xva18Qj^9voJ8n4tut_CzmJ~upFsxQ8Ax|9>e=DnVlT8^0(z!ujb ztdXmV9w`~67qu&TeU{vyA~i+GGy28W;tEzT;?6X~si=yr`}#t8pIbjZ*&W(5?FXxC z<3WdOGIx{d>KeU^brt+xCsW^N;IM;NtIrQ9GqkXs7=xONt6o)piB7$o09G{VEr0YT z(&Mn}{?j}&G)klc5Ez1d)^LWQwdnlFMt4PcugBhTxw7uy&WgfBJhg>SL}PVBHV21w zJ_n{=FN9vf`4tZLV+7z2c8%#}KFir8mVT_M0tRXjfQwax6Yd={Ub2hV$XXe%%{W;x z2Vt)8yh6N_22Atja6?57HbV36ju!UP0cu88k!biN$F1ehD4kkjgo!u5 zD8hetEAb8joG-x-{C5Z|5o`{DGw6f5Vss8e7I7rbKfwmDN z!_WMnc=i)j*T4SnTE7b&BmTF8bOvlvzh@0n6%=rkd-J}vnIq4}czUR)4YLn4CO>OWj>g>N@z*}a*UfFS6hz1!YR;tnm@9g*J5W}e zyh!apE$`5fd#6u5kC{nPP;;LQbyH9!r)E1Q@SLTI)yra=<`bf$*rd5PkJFFoCAF?A?Ql=gnmkcIMVUQ6un$)>H|4YvVr1&YLnkIK% zsKrty8eOcSFX$?JfkwweNv7s!gI&l;1XO=EoV6z7p*2({7MU%YRgbGJ!ouA}J223W z?c2-6mnH7lIDikZHWiSi7Ao)X&V`ukrqQ3+$t4f!*a)VYxZo109T7{!$vG#!ETWEd z5~J#?%JILuu@ZewN1I17zAXo;mdZRb<%Vq$l{%pxo3+TwXqAuDhSNDJ6twjWt(}*1 zO&s3QMnmp02D3>Cjuc224W{L8lL}bvO=B6g%j0C5yaB8YpQD+(q0NoFg{++6zKGH! zhQCHjCsw|X+H>=ti+aXObi*-M53)FF7oC2HV%zt!CGob-G?BJSJsMsn5w>ieXm~;@ zSR~cvOG^CN1*gUs7B7?As{tj}ZA+$3!FTmz5H^2XBQu}gl)3}a+PUU2r8ifjkPg4< zATy9@LlS*A{n9V-9S5BSQLnU2qVGTUKqhaOn=>P0fmUbjAV++*iUJaqQI&UH6UXbth+C}r7Y!X53sW9% z`VrSVbWzOPgCed^y(uGzV`A_nR zS;}}sJUBb;OnC?X4W>HarYyQ8`pUs~qd`JI!EV@YR%v9P_g; zFAQVUl^uZ(F6POg#PfVjCI0rr#56~@<61%o&_TPDLGeY6sqiw=&SSfLy`r@dbw=Rv;hYmZ%b{jk}w*ParFG$;3t6(BKZ* zsdtH+lZ&~&?;i0~>O`!H{a*r;eYHTLS%}MeWW4tQ>k>Kq50-mIG`RJTVIhLR@7lJ) z;KW$`2p$PKDg|lB{V4HWbv`||XaI!q;&kM1#koZ`UY`NQ+aP%;tATH(7eiqMTa+(e z!`lb*d|f_B8gY*?Thl9U;*u-A7w>7B%k}eSk9|s%nfGi7)kUyP^C95Hr=bS07Wd~l z?xgzeaEt_w;nYZEh}e^>`1{aq&1CT~dm${x$llqA%VTGW>KtRhG}(1MEYqkD^zT5;{`3(28&6sJm&5So=rwd_M9>|gBf zVJqye?2usbOOfH~cdzgJM%%|DBW+V4!aJA7pCZk;)n6zqC=PCBH0jR@>c1G1zQLA3 zzwQ%ql*S*BJ_U6vREo=55ixNN$AN(gPD1?STcjndBgLw* z|D<4m0*74}4E-=G!-Onat%cS&2m`?s5KXWxSk{qtK=KfZLEHaRr&;}47S~uVFhuVA zqVx})Lg%L@-xzKq6$zidLA@BL25NkWs8Sy5O%M0m1`m}XGaShvwTV!cWQRZNY5{5e2jFI1Q%l+e(Anq)-hgeig47x$OVH^J%>`->)3n^V$V-X zo=@_amm`H%e|s$@M8Un(1MT?(AIq=BDh9YKC82q5E7b-_YjBj1p#Cfhxe}b=(#p{T zEu})gwDybMDq6XA6`t||GT6lv6nm4X`0G@Pw+rRjBqC{oj zWDYcStTu>LE%xncU70*Kk@weT>y??h(wXv%5tWLZ9K2R#bW}>7Nr4mgxTI7jXp8N+ zsY64RemTlbCQtek=DdMJ_ns!+(oHRCi#`yxVXsb0b53^ZXn5cVDP2rykWH6HO>+_w zeNt8Ha~%JWD)c-)O(HrexS3{ut#RfC`{xLIwW>htNbM}6fvRk!y6GXh`9`2BG5l%f z$V9!-9C{6wmlHu1(cD13xJzrpGAa*hcSLws8r9s8%+2>WVkQk(Pkm(9DL=MGm>p+6 zRq(I_70E(CT>esuPm?_8ZF%3d(I~Z`f~rZ4SdAG;-7G51JL#D`itng(szj7?k?&be zX02amkIX5K_=%kgDO^Y^ph6<**Q8|32*b07l&(@WsZvHD|L^HJ*U^{N zTWwb!M2$vffDsGG9?C`?cK~8~9M-NeZv{tai|XpS>%SsXbH+t%f1RC4oU8pr76#XQ z5*l-RMmX-&I5m9@u7VdH&3yZ$XE1@#V^uL#Rp|24i!oZ%r-MHs!AbrJRQjk zX{-xYv+!Rs`t2*YNKiW#C4UfW_2PG9QUF681Rg=O7&i!e+D!2wl&a%JxKNIdtLP8= zEqNJhL1c}peRZBhGIl#hF>mI2;N`CuRp?wO}S1-YKwmtl|Mh6R41; ziObN%HeQJUZUBN#|75(U%X?&NU`&?WJ*OL{{^NJgIl^n3@^Jf}^s7l6v^_SIT zSGHg@qZXHvR@rioLFLS*tO53p#x%iNe81@_>l(GB;XfU<-R!j`$ZT%8$*lpwVfNH2 zt=Qf~>tB#2?2oBss_6o9^-vZtKW=tS0U%ulEUy|<(hXh8t~vFupZQO{#%sKTOa3G> zdYfjJ=+-R&SPv!?+IQo?o-|s(T|e8&$B@&)`O)&ed8PSgmF(>%F8$~R!^Q~jro}T~ z1CCOe=!nUL$^6MGPSI-NzoqSGGkQ@#voYL&ay}Q`$VPRkZE&^Mexd&@YU|Ua`Ln7a zt&L&&P8Cs@@(;>n>l@80)wK;b6`vh#v@FHUS<@LeLX!!L*K1S6dM%_~#&%W4SeBLv zS~NT%I`87PK48qi8W%Gs4CBx(d74QhR~NgVEiObiF>hzc<~3$QSMcUdsZ8nLCvPz9 zlA~j2wmgdydsuP+ti+oC-(#t*JhWuU8TK|YKL>n2`fYNCtG<~!_W1#+p_{6=YxRcB z3NKC`&D2^hXA5U-&TtneP}U3=Z_D@x(lo%-7{lhasUCp$eK30q`n+>*yR=^?Oshzb5u=v(0IBvBv=dj9jrJ4;mj^mI31y)qs zq%|K@P}w${5~aqOOY$5Qu9>&<_11Y?+o1wApWtJFE{ldaHNL zr|OUvvUhr8H=J`Utz|meMKIUlc%14uae6FL=Qy>yOS6o7g5c(x5pxPkGoPb6_W0q1 Y2yj}6b6U)CTB>$hrjPsm>Xq>S01LIR)c^nh literal 0 HcmV?d00001 diff --git a/tools/ddr_init.c b/tools/ddr_init.c new file mode 100644 index 0000000..1a5863e --- /dev/null +++ b/tools/ddr_init.c @@ -0,0 +1,88 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma DDR Initialization + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/17/05 + * FILENAME: ddr_init.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma DDR Initialization + * Supports 64MB (512Mb) MT46V32M16 by default. + * For 32 MB and 128 MB DDR parts change AddressLines and Bank shift: + * For 32 MB change 13->12 and 11->10. MT46V16M16 + * For 128 MB change 13->14 and 11->12. MT46V64M16 + *--------------------------------------------------------------------*/ +#define DDR_BASE 0x10000000 +#define MemoryRead(A) (*(volatile int*)(A)) +#define MemoryWrite(A,V) *(volatile int*)(A)=(V) + +extern int putchar(int value); +extern int puts(const char *string); +extern void print_hex(unsigned long num); + +//SD_A <= address_reg(25 downto 13); --address row +//SD_BA <= address_reg(12 downto 11); --bank_address +//cmd := address_reg(6 downto 4); --bits RAS & CAS & WE +int DdrInitData[] = { +// AddressLines Bank Command + (0x000 << 13) | (0 << 11) | (7 << 4), //CKE=1; NOP="111" + (0x400 << 13) | (0 << 11) | (2 << 4), //A10=1; PRECHARGE ALL="010" +#ifndef DLL_DISABLE + (0x000 << 13) | (1 << 11) | (0 << 4), //enable DLL; BA="01"; LMR="000" +#else + (0x001 << 13) | (1 << 11) | (0 << 4), //disable DLL; BA="01"; LMR="000" +#endif + (0x121 << 13) | (0 << 11) | (0 << 4), //reset DLL, CL=2, BL=2; LMR="000" + (0x400 << 13) | (0 << 11) | (2 << 4), //A10=1; PRECHARGE ALL="010" + (0x000 << 13) | (0 << 11) | (1 << 4), //AUTO REFRESH="001" + (0x000 << 13) | (0 << 11) | (1 << 4), //AUTO REFRESH="001 + (0x021 << 13) | (0 << 11) | (0 << 4) //clear DLL, CL=2, BL=2; LMR="000" +}; + +int DdrInit(void) +{ + int i, j, k=0; + for(i = 0; i < sizeof(DdrInitData)/sizeof(int); ++i) + { + MemoryWrite(DDR_BASE + DdrInitData[i], 0); + for(j = 0; j < 4; ++j) + ++k; + } + for(j = 0; j < 100; ++j) + ++k; + k += MemoryRead(DDR_BASE); //Enable DDR + return k; +} + +#ifdef DDR_TEST_MAIN +int main() +{ + volatile int *ptr = (int*)DDR_BASE; + int i; + + DdrInit(); + + ptr[0] = 0x12345678; + if(ptr[0] != 0x12345678) + putchar('X'); + for(i = 0; i < 10; ++i) + { + ptr[i] = i; + } + + for(i = 0; i < 10; ++i) + { + if(ptr[i] != i) + putchar('A' + i); + } + *(unsigned char*)DDR_BASE = 0x23; + *(unsigned char*)(DDR_BASE+1) = 0x45; + *(unsigned char*)(DDR_BASE+2) = 0x67; + *(unsigned char*)(DDR_BASE+3) = 0x89; + if(ptr[0] != 0x23456789) + putchar('Y'); + puts("\r\ndone\r\n"); + return 0; +} +#endif diff --git a/tools/etermip.c b/tools/etermip.c new file mode 100644 index 0000000..8120529 --- /dev/null +++ b/tools/etermip.c @@ -0,0 +1,448 @@ +/*-------------------------------------------------------------------- + * TITLE: etermip + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 6/13/07 + * FILENAME: etermip.c + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * A terminal program supporting downloading new Plasma applications + * and Ethernet packet transfers. Based on WinPcap example code. + * Requires WinPcap library at http://www.winpcap.org/. + *--------------------------------------------------------------------*/ +#include +#include +#include + +//#define SIMULATE_PLASMA +//#define USE_WPCAP +#ifdef SIMULATE_PLASMA +#define USE_WPCAP +#endif + +#ifdef USE_WPCAP +#if 0 + #include "pcap.h" +#else + //From "pcap.h" + #define PCAP_ERRBUF_SIZE 256 + typedef struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + unsigned long flags; /* PCAP_IF_ interface flags */ + } pcap_if_t; + struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + unsigned long caplen; /* length of portion present */ + unsigned long len; /* length this packet (off wire) */ + }; + typedef struct pcap pcap_t; + + int pcap_findalldevs(pcap_if_t **, char *); + void pcap_freealldevs(pcap_if_t *); + pcap_t *pcap_open_live(const char *, int, int, int, char *); + int pcap_setnonblock(pcap_t *, int, char *); + int pcap_sendpacket(pcap_t *, const u_char *, int); + const unsigned char *pcap_next(pcap_t *, struct pcap_pkthdr *); +#endif + +//ETHER FIELD OFFSET LENGTH VALUE +#define ETHERNET_DEST 0 //6 +#define ETHERNET_SOURCE 6 //6 +#define ETHERNET_FRAME_TYPE 12 //2 IP=0x0800; ARP=0x0806 +#define IP_PROTOCOL 23 //1 TCP=0x06;PING=0x01;UDP=0x11 +#define IP_SOURCE 26 //4 + +static const unsigned char ethernetAddressNull[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const unsigned char ethernetAddressPhantom[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4}; +static const unsigned char ethernetAddressPhantom2[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd5}; + +static pcap_t *adhandle; +#endif //USE_WPCAP + +static HANDLE serial_handle; +static int PacketBytes, PacketLength, PacketChecksum, Checksum; +static int ChecksumOk, ChecksumError; +static unsigned char PacketData[2000]; +static int EthernetActive; + +#ifdef SIMULATE_PLASMA + extern void *IPFrameGet(int freeCount); + extern int IPProcessEthernetPacket(void *frameIn, int length); + extern void IPTick(void); + extern void IPInit(void (*frameSendFunction)(), unsigned char macAddress[6], char name[6]); + extern void HtmlInit(int UseFiles); + extern void ConsoleInit(void); + static void *ethFrame; +#endif + + +#ifdef USE_WPCAP +int WinPcapInit(void) +{ + pcap_if_t *alldevs; + pcap_if_t *d; + int inum; + int i=0; + int choice = -1; + char errbuf[PCAP_ERRBUF_SIZE]; + + /* Retrieve the device list */ + if(pcap_findalldevs(&alldevs, errbuf) == -1) + { + printf("Error in pcap_findalldevs: %s\n", errbuf); + exit(1); + } + + /* Print the list */ + for(d = alldevs; d; d=d->next) + { + printf("%d. %s", ++i, d->name); + if (d->description) + printf(" (%s)\n", d->description); + else + printf(" (No description available)\n"); + if(strstr(d->description, "eneric") == 0 && strstr(d->description, "Linux") == 0) + { + if(choice == -1) + choice = i; + else + choice = -2; + } + } + + if(i==0) + { + printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); + return -1; + } + + if(choice >= 0) + inum = choice; + else if(i == 1) + inum = 1; + else + { + printf("Enter the interface number (1-%d):",i); + scanf("%d", &inum); + } + printf("inum = %d\n", inum); + + if(inum < 1 || inum > i) + { + printf("\nInterface number out of range.\n"); + /* Free the device list */ + pcap_freealldevs(alldevs); + return -1; + } + + /* Jump to the selected adapter */ + for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); + + /* Open the adapter */ + if ((adhandle = pcap_open_live(d->name, // name of the device + 65536, // 65536 grants that the whole packet will be captured on all the MACs. + 1, // promiscuous mode (nonzero means promiscuous) + 10, // read timeout + errbuf // error buffer + )) == NULL) + { + printf("\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); + /* Free the device list */ + pcap_freealldevs(alldevs); + return -1; + } + + printf("\nlistening on %s...\n", d->description); + + /* At this point, we don't need any more the device list. Free it */ + pcap_freealldevs(alldevs); + + /* start the capture */ + pcap_setnonblock(adhandle, 1, errbuf); + + return 0; +} + + +void EthernetSendPacket(const unsigned char *packet, int length) +{ + if(EthernetActive == 0) + WinPcapInit(); + EthernetActive = 1; + //if((rand() % 8) == 0) return; + pcap_sendpacket(adhandle, packet, length); +} + + +/* Callback function invoked by libpcap for every incoming packet */ +void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) +{ +#ifndef SIMULATE_PLASMA + int i, checksum; + unsigned char buf[80]; + DWORD count; +#else + int rc; +#endif + (void)param; + + if(EthernetActive == 0) + return; + if(pkt_data[ETHERNET_FRAME_TYPE] != 0x08) + return; //not IP or ARP + if(pkt_data[ETHERNET_FRAME_TYPE+1] != 0x00 && + pkt_data[ETHERNET_FRAME_TYPE+1] != 0x06) + return; //not IP or ARP + if(memcmp(pkt_data, ethernetAddressNull, 6) && //not broadcast address + memcmp(pkt_data+ETHERNET_DEST, ethernetAddressPhantom, 6) && + memcmp(pkt_data+ETHERNET_DEST, ethernetAddressPhantom2, 6)) + return; + +#ifndef SIMULATE_PLASMA + //Send the ethernet packet over the serial port + buf[0] = 0xff; + buf[1] = (unsigned char)(header->len >> 8); + buf[2] = (unsigned char)header->len; + checksum = 0; + for(i = 0; i < (int)header->len; ++i) + checksum += pkt_data[i]; + buf[3] = (unsigned char)checksum; + WriteFile(serial_handle, buf, 4, &count, NULL); + WriteFile(serial_handle, pkt_data, header->len, &count, NULL); +#else + if(ethFrame == NULL) + ethFrame = IPFrameGet(0); + if(ethFrame == NULL) + return; + memcpy(ethFrame, pkt_data, header->len); + rc = IPProcessEthernetPacket(ethFrame, header->len); + if(rc) + ethFrame = NULL; +#endif +} + + +static void UartPacketRead(int value) +{ + if(PacketBytes == 0 && value == 0xff) + { + ++PacketBytes; + } + else if(PacketBytes == 1) + { + ++PacketBytes; + PacketLength = value << 8; + } + else if(PacketBytes == 2) + { + ++PacketBytes; + PacketLength |= value; + if(PacketLength > 1000) + { + PacketBytes = 0; + printf("Eterm Length Bad! (%d)\n", PacketLength); + } + } + else if(PacketBytes == 3) + { + ++PacketBytes; + PacketChecksum = value; + Checksum = 0; + } + else if(PacketBytes >= 4) + { + if(PacketBytes - 4 < sizeof(PacketData)) + PacketData[PacketBytes - 4] = (unsigned char)value; + Checksum += value; + ++PacketBytes; + if(PacketBytes - 4 >= PacketLength) + { + if((unsigned char)Checksum == PacketChecksum) + { + ++ChecksumOk; + EthernetSendPacket(PacketData, PacketLength); + } + else + { + ++ChecksumError; + //printf("ChecksumError(%d %d)!\n", ChecksumOk, ChecksumError); + } + PacketBytes = 0; + } + } +} +#endif //USE_WPCAP + +/**************************************************************/ + +long SerialOpen(char *name, long baud) +{ + DCB dcb; + COMMTIMEOUTS comm_timeouts; + BOOL rc; + serial_handle = CreateFile(name, GENERIC_READ|GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if(serial_handle == INVALID_HANDLE_VALUE) + printf("Serial Port In Use!\n"); + rc = SetupComm(serial_handle, 16000, 16000); + if(rc == FALSE) + printf("Serial port already in use!!!\n"); + rc = GetCommState(serial_handle, &dcb); + if(rc == FALSE) + printf("ERROR2\n"); + dcb.BaudRate = baud; + dcb.fBinary = 1; + dcb.fParity = 0; + dcb.ByteSize = 8; + dcb.StopBits = 0; //ONESTOPBIT; + dcb.fOutX = 0; + dcb.fInX = 0; + dcb.fNull = 0; + dcb.Parity = 0; + dcb.fOutxCtsFlow = 0; + dcb.fOutxDsrFlow = 0; + dcb.fOutX = 0; + dcb.fInX = 0; + dcb.fRtsControl = 0; + dcb.fDsrSensitivity = 0; + rc = SetCommState(serial_handle, &dcb); + if(rc == FALSE) + printf("ERROR3\n"); + rc = GetCommTimeouts(serial_handle, &comm_timeouts); + if(rc == FALSE) + printf("ERROR4\n"); + comm_timeouts.ReadIntervalTimeout = MAXDWORD; //non-blocking read + comm_timeouts.ReadTotalTimeoutMultiplier = 0; + comm_timeouts.ReadTotalTimeoutConstant = 0; + comm_timeouts.WriteTotalTimeoutMultiplier = 0; //blocking write + comm_timeouts.WriteTotalTimeoutConstant = 0; + rc = SetCommTimeouts(serial_handle, &comm_timeouts); + if(rc == FALSE) + printf("ERROR5\n"); + return(0); +} + + +long SerialRead(unsigned char *data, unsigned long length) +{ + DWORD count, bytes; + unsigned char buf[8]; + + count = 0; + for(;;) + { + ReadFile(serial_handle, buf, 1, &bytes, NULL); + if(bytes == 0) + break; +#ifdef USE_WPCAP + if(buf[0] == 0xff || PacketBytes) + UartPacketRead(buf[0]); + else +#endif + data[count++] = buf[0]; + if(count >= length) + break; + } + return count; +} + +//**************************************************** + +#define BUF_SIZE 1024*1024 +void SendFile(void) +{ + FILE *in; + unsigned char *buf; + long length; + DWORD count; + + in=fopen("test.bin", "rb"); + if(in==NULL) { + printf("Can't find test.bin\n"); + return; + } + buf = (unsigned char*)malloc(BUF_SIZE); + memset(buf, 0, BUF_SIZE); + length = (int)fread(buf, 1, BUF_SIZE, in); + fclose(in); + printf("Sending test.bin (length=%d bytes) to target...\n", length); + WriteFile(serial_handle, buf, length, &count, NULL); + printf("Done downloading\n"); + free(buf); +} + + +int main(int argc, char *argv[]) +{ + unsigned int ticksLast = GetTickCount(); + int length; + unsigned char buf[80]; + DWORD count; + unsigned int ticks; + int downloadSkip = 0; + (void)argc; + (void)argv; + + //WinPcapInit(); +#ifndef SIMULATE_PLASMA + SerialOpen("COM1", 57600); + if(argc != 2 || strcmp(argv[1], "none")) + SendFile(); + else + downloadSkip = 1; +#else + IPInit(EthernetSendPacket, NULL, NULL); + HtmlInit(1); + ConsoleInit(); +#endif + + for(;;) + { + // Read keypresses + while(kbhit()) + { + buf[0] = (unsigned char)getch(); + if(downloadSkip && buf[0] == '`') + SendFile(); + WriteFile(serial_handle, buf, 1, &count, NULL); + } + + // Read UART + for(;;) + { + length = SerialRead(buf, sizeof(buf)); + if(length == 0) + break; + buf[length] = 0; + printf("%s", buf); + } + +#ifdef USE_WPCAP + // Read Ethernet + while(EthernetActive) + { + struct pcap_pkthdr header; + const u_char *pkt_data; + pkt_data = pcap_next(adhandle, &header); + if(pkt_data == NULL) + break; + if(EthernetActive) + packet_handler(NULL, &header, pkt_data); + } +#endif + Sleep(10); + ticks = GetTickCount(); + if(ticks - ticksLast > 1000) + { +#ifdef SIMULATE_PLASMA + IPTick(); +#endif + ticksLast = ticks; + } + } +} + diff --git a/tools/makefile b/tools/makefile new file mode 100644 index 0000000..73c140a --- /dev/null +++ b/tools/makefile @@ -0,0 +1,284 @@ +# The CC_X86 is for compiling tools on your PC. +# The GCC_MIPS is for compiling code on the target. +# Convert_bin changes test.axf into code.txt which is used by the VHDL. +# Convert_bin == "objcopy -I elf32-big -O binary test.axf test.bin" + + +ifeq ($(LANG),) + +# Customize for Windows +# The MIPS gcc compiler must use the cygwin1.dll that came with the compiler. +CC_X86 = cl /O1 /nologo +CP = copy +RM = del +DWIN32 = -DWIN32 +BIN_MIPS = ..\gccmips_elf +VHDL_DIR = ..\vhdl +LINUX_PWD = +GCC_MIPS = $(BIN_MIPS)\gcc $(CFLAGS) +AS_MIPS = $(BIN_MIPS)\as +LD_MIPS = $(BIN_MIPS)\ld +DUMP_MIPS = $(BIN_MIPS)\objdump +CONVERT_BIN = $(LINUX_PWD)convert_bin.exe + +else + +# Customized for Linux +# See http://www.opencores.com/projects.cgi/web/mips/linux_tools.htm +CC_X86 = gcc -Wall -O -g +CP = cp +RM = rm -rf +DWIN32 = +BIN_MIPS = +VHDL_DIR = ../vhdl +LINUX_PWD = ./ +GCC_MIPS = $(BIN_MIPS)mips-elf-gcc $(CFLAGS) +AS_MIPS = $(BIN_MIPS)mips-elf-as +LD_MIPS = $(BIN_MIPS)mips-elf-ld +DUMP_MIPS = $(BIN_MIPS)mips-elf-objdump +CONVERT_BIN = $(LINUX_PWD)convert_bin.exe +#CONVERT_BIN = $(BIN_MIPS)mips-elf-objcopy -I elf32-big -O binary test.axf test.bin + +endif + +CFLAGS = -O2 -Wall -c -s + +all: convert_bin.exe tracehex.exe bintohex.exe ram_image.exe + @echo make targets = count, opcodes, pi, test, run, tohex,\ + bootldr, toimage, eterm + +clean: + -$(RM) *.o *.obj *.map *.lst *.hex *.txt *.exe *.axf + +#Same as "objcopy -I elf32-big -O binary test.axf test.bin" +convert_bin.exe: convert.c + @$(CC_X86) -o convert_bin.exe convert.c + +convert_le.exe: convert.c + @$(CC_X86) -DLITTLE_ENDIAN -o convert_le.exe convert.c + +mlite.exe: mlite.c + @$(CC_X86) -o mlite.exe mlite.c $(DWIN32) + +tracehex.exe: tracehex.c + @$(CC_X86) -o tracehex.exe tracehex.c + +bintohex.exe: bintohex.c + @$(CC_X86) -o bintohex.exe bintohex.c + +ram_image.exe: ram_image.c + @$(CC_X86) -o ram_image.exe ram_image.c + +# Terminal program that will download a new image. +# For Linux, use any serial port program at 57600 baud 8-bits;1-stop bit +# This mode does not support Ethernet packet transfers. +eterm: etermip.c + -@$(CC_X86) -o etermip.exe etermip.c + +# Terminal program that will download a new image and supports Ethernet +# traffic over UART. Get wpcap.lib from http://www.winpcap.org/. +# Requires Windows OS +# Uses wpcap.lib for receiving and transmitting raw Ethernet packets +# Get wpcap.lib from http://www.winpcap.org/. +etermip: etermip.c + @echo Get wpcap.lib from http://www.winpcap.org/ + -@$(CC_X86) -DUSE_WPCAP -o etermip.exe etermip.c wpcap.lib + +nomult.exe: nomult.c + -@$(CC_X86) -o nomult.exe nomult.c + +download: etermip + @echo Reset board before downloading code + etermip + +opcodes: + $(AS_MIPS) -o opcodes.o opcodes.asm + $(LD_MIPS) -Ttext 0 -eentry -Map test.map -s -N -o test.axf opcodes.o + -@$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +opcodes2: + $(AS_MIPS) -o opcodes.o opcodes.asm + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf opcodes.o + -@$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +test: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) test.c + $(GCC_MIPS) no_os.c + $(LD_MIPS) -Ttext 0 -eentry -Map test.map -s -N -o test.axf \ + boot.o test.o no_os.o + -@$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +count: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) count.c + $(GCC_MIPS) no_os.c + $(LD_MIPS) -Ttext 0 -eentry -Map test.map -s -N -o test.axf \ + boot.o count.o no_os.o + -$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +count_le: + $(AS_MIPS) -EL -o boot.o boot.asm + $(GCC_MIPS) -EL count.c + $(GCC_MIPS) -EL no_os.c + $(LD_MIPS) -EL -Ttext 0 -eentry -Map test.map -s -N -o test.axf \ + boot.o count.o no_os.o + -$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +count2: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) count.c + $(GCC_MIPS) no_os.c + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf \ + boot.o count.o no_os.o + -$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +count3: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) count.c + $(GCC_MIPS) no_os.c + $(LD_MIPS) -Ttext 0x2000 -eentry -Map test.map -s -N -o test.axf \ + boot.o count.o no_os.o + -$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +count5: nomult.exe + $(AS_MIPS) -o boot.o boot.asm + $(AS_MIPS) -o mult_sim.o mult_sim.asm + $(GCC_MIPS) count.c + $(GCC_MIPS) no_os.c + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf \ + boot.o mult_sim.o count.o no_os.o + -$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CP) test.axf test_old.axf + nomult test.axf test.lst test.map + -$(DUMP_MIPS) --disassemble test.axf > test2.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +pi: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) pi.c + $(LD_MIPS) -Ttext 0 -eentry -Map test.map -s -N -o test.axf \ + boot.o pi.o + @$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +pi2: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) pi.c + $(LD_MIPS) -Ttext 0x10000000 -eentry -Map test.map -s -N -o test.axf \ + boot.o pi.o + @$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +pi5: nomult.exe + $(AS_MIPS) -o boot.o boot.asm + $(AS_MIPS) -o mult_sim.o mult_sim.asm + $(GCC_MIPS) pi.c + $(LD_MIPS) -Ttext 0x0 -eentry -Map test.map -s -N -o test.axf \ + boot.o mult_sim.o pi.o + @$(DUMP_MIPS) --disassemble test.axf > test.lst + nomult test.axf test.lst test.map + @$(DUMP_MIPS) --disassemble test.axf > test2.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +ddr_test: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) ddr_init.c -DDDR_TEST_MAIN + $(GCC_MIPS) no_os.c + $(LD_MIPS) -Ttext 0x0 -eentry -Map test.map -s -N -o test.axf \ + boot.o ddr_init.o no_os.o + @$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +memtest: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) memtest.c + $(LD_MIPS) -Ttext 0x2000 -eentry -o test.axf boot.o memtest.o + $(CONVERT_BIN) + +memtest2: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) -DINIT_DDR memtest.c + $(GCC_MIPS) ddr_init.c + $(LD_MIPS) -Ttext 0x0 -eentry -o test.axf boot.o memtest.o ddr_init.o + $(CONVERT_BIN) + +memtest3: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) memtest.c + $(LD_MIPS) -Ttext 0x10000000 -eentry -o test.axf boot.o memtest.o + $(CONVERT_BIN) + +bootldr: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) bootldr.c + $(GCC_MIPS) no_os.c + $(GCC_MIPS) -DDLL_DISABLE ddr_init.c + $(LD_MIPS) -Ttext 0 -eentry -Map test.map -s -N -o test.axf \ + boot.o bootldr.o no_os.o ddr_init.o + @$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + @echo Next do "make toimage" for Xilinx or "make tohex" for Altera. + +bootldr2: + $(AS_MIPS) -o boot.o boot.asm + $(GCC_MIPS) bootldr.c + $(GCC_MIPS) no_os.c + $(GCC_MIPS) -DDLL_DISABLE ddr_init.c + $(LD_MIPS) -Ttext 0x1000 -eentry -Map test.map -s -N -o test.axf \ + boot.o bootldr.o no_os.o ddr_init.o + @$(DUMP_MIPS) --disassemble test.axf > test.lst + $(CONVERT_BIN) + $(CP) code.txt $(VHDL_DIR) + +bootldr_little_endian: convert_le.exe + $(AS_MIPS) -EL -o boot.o boot.asm + $(GCC_MIPS) -EL bootldr.c + $(GCC_MIPS) -EL no_os.c + $(GCC_MIPS) -EL ddr_init.c + $(LD_MIPS) -EL -Ttext 0 -eentry -Map test.map -s -N -o test.axf \ + boot.o bootldr.o no_os.o ddr_init.o + @$(DUMP_MIPS) --disassemble test.axf > test.lst + $(LINUX_PWD)convert_le.exe + $(CP) code.txt $(VHDL_DIR) + +# Run a MIPS opcode simulator +run: mlite.exe + @$(LINUX_PWD)mlite.exe test.bin + +run_little_endian: mlite.exe + @$(LINUX_PWD)mlite.exe test.bin L + +disassemble: mlite.exe + $(LINUX_PWD)mlite.exe test.bin BD > test.txt + +# Used by Altera FPGAs for ram image +tohex: bintohex.exe + $(LINUX_PWD)bintohex.exe test.bin + $(CP) code*.hex $(VHDL_DIR) + +# Used by Xilinx FPGAs for ram image +toimage: + $(LINUX_PWD)ram_image.exe ../vhdl/ram_xilinx.vhd ../vhdl/code.txt ../vhdl/ram_image.vhd + + diff --git a/tools/mlite.c b/tools/mlite.c new file mode 100644 index 0000000..34d4d11 --- /dev/null +++ b/tools/mlite.c @@ -0,0 +1,999 @@ +/*------------------------------------------------------------------- +-- TITLE: Plasma CPU in software. Executes MIPS(tm) opcodes. +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 1/31/01 +-- FILENAME: mlite.c +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Plasma CPU simulator in C code. +-- This file served as the starting point for the VHDL code. +-- Assumes running on a little endian PC. +--------------------------------------------------------------------*/ +#include +#include +#include +#include +#include + +//#define ENABLE_CACHE +#define SIMPLE_CACHE + +#define MEM_SIZE (1024*1024*2) +#define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) ) +#define htons(A) ntohs(A) +#define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) ) +#define htonl(A) ntohl(A) + +#ifndef WIN32 +//Support for Linux +#define putch putchar +#include +#include + +void Sleep(unsigned int value) +{ + usleep(value * 1000); +} + +int kbhit(void) +{ + struct termios oldt, newt; + struct timeval tv; + fd_set read_fd; + + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + tv.tv_sec=0; + tv.tv_usec=0; + FD_ZERO(&read_fd); + FD_SET(0,&read_fd); + if(select(1, &read_fd, NULL, NULL, &tv) == -1) + return 0; + //tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + if(FD_ISSET(0,&read_fd)) + return 1; + return 0; +} + +int getch(void) +{ + struct termios oldt, newt; + int ch; + + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + ch = getchar(); + //tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return ch; +} +#else +//Support for Windows +#include +extern void __stdcall Sleep(unsigned long value); +#endif + +#define UART_WRITE 0x20000000 +#define UART_READ 0x20000000 +#define IRQ_MASK 0x20000010 +#define IRQ_STATUS 0x20000020 +#define CONFIG_REG 0x20000070 +#define MMU_PROCESS_ID 0x20000080 +#define MMU_FAULT_ADDR 0x20000090 +#define MMU_TLB 0x200000a0 + +#define IRQ_UART_READ_AVAILABLE 0x001 +#define IRQ_UART_WRITE_AVAILABLE 0x002 +#define IRQ_COUNTER18_NOT 0x004 +#define IRQ_COUNTER18 0x008 +#define IRQ_MMU 0x200 + +#define MMU_ENTRIES 4 +#define MMU_MASK (1024*4-1) + +typedef struct +{ + unsigned int virtualAddress; + unsigned int physicalAddress; +} MmuEntry; + +typedef struct { + int r[32]; + int pc, pc_next, epc; + unsigned int hi; + unsigned int lo; + int status; + int userMode; + int processId; + int exceptionId; + int faultAddr; + int irqStatus; + int skip; + unsigned char *mem; + int wakeup; + int big_endian; + MmuEntry mmuEntry[MMU_ENTRIES]; +} State; + +static char *opcode_string[]={ + "SPECIAL","REGIMM","J","JAL","BEQ","BNE","BLEZ","BGTZ", + "ADDI","ADDIU","SLTI","SLTIU","ANDI","ORI","XORI","LUI", + "COP0","COP1","COP2","COP3","BEQL","BNEL","BLEZL","BGTZL", + "?","?","?","?","?","?","?","?", + "LB","LH","LWL","LW","LBU","LHU","LWR","?", + "SB","SH","SWL","SW","?","?","SWR","CACHE", + "LL","LWC1","LWC2","LWC3","?","LDC1","LDC2","LDC3" + "SC","SWC1","SWC2","SWC3","?","SDC1","SDC2","SDC3" +}; + +static char *special_string[]={ + "SLL","?","SRL","SRA","SLLV","?","SRLV","SRAV", + "JR","JALR","MOVZ","MOVN","SYSCALL","BREAK","?","SYNC", + "MFHI","MTHI","MFLO","MTLO","?","?","?","?", + "MULT","MULTU","DIV","DIVU","?","?","?","?", + "ADD","ADDU","SUB","SUBU","AND","OR","XOR","NOR", + "?","?","SLT","SLTU","?","DADDU","?","?", + "TGE","TGEU","TLT","TLTU","TEQ","?","TNE","?", + "?","?","?","?","?","?","?","?" +}; + +static char *regimm_string[]={ + "BLTZ","BGEZ","BLTZL","BGEZL","?","?","?","?", + "TGEI","TGEIU","TLTI","TLTIU","TEQI","?","TNEI","?", + "BLTZAL","BEQZAL","BLTZALL","BGEZALL","?","?","?","?", + "?","?","?","?","?","?","?","?" +}; + +static unsigned int HWMemory[8]; + + +static int mem_read(State *s, int size, unsigned int address) +{ + unsigned int value=0, ptr; + + s->irqStatus |= IRQ_UART_WRITE_AVAILABLE; + switch(address) + { + case UART_READ: + if(kbhit()) + HWMemory[0] = getch(); + s->irqStatus &= ~IRQ_UART_READ_AVAILABLE; //clear bit + return HWMemory[0]; + case IRQ_MASK: + return HWMemory[1]; + case IRQ_MASK + 4: + Sleep(10); + return 0; + case IRQ_STATUS: + if(kbhit()) + s->irqStatus |= IRQ_UART_READ_AVAILABLE; + return s->irqStatus; + case MMU_PROCESS_ID: + return s->processId; + case MMU_FAULT_ADDR: + return s->faultAddr; + } + + ptr = (unsigned int)s->mem + (address % MEM_SIZE); + + if(0x10000000 <= address && address < 0x10000000 + 1024*1024) + ptr += 1024*1024; + + switch(size) + { + case 4: + if(address & 3) + printf("Unaligned access PC=0x%x address=0x%x\n", (int)s->pc, (int)address); + assert((address & 3) == 0); + value = *(int*)ptr; + if(s->big_endian) + value = ntohl(value); + break; + case 2: + assert((address & 1) == 0); + value = *(unsigned short*)ptr; + if(s->big_endian) + value = ntohs((unsigned short)value); + break; + case 1: + value = *(unsigned char*)ptr; + break; + default: + printf("ERROR"); + } + return(value); +} + +static void mem_write(State *s, int size, int unsigned address, unsigned int value) +{ + unsigned int ptr; + + switch(address) + { + case UART_WRITE: + putch(value); + fflush(stdout); + return; + case IRQ_MASK: + HWMemory[1] = value; + return; + case IRQ_STATUS: + s->irqStatus = value; + return; + case CONFIG_REG: + return; + case MMU_PROCESS_ID: + //printf("processId=%d\n", value); + s->processId = value; + return; + } + + if(MMU_TLB <= address && address <= MMU_TLB+MMU_ENTRIES * 8) + { + //printf("TLB 0x%x 0x%x\n", address - MMU_TLB, value); + ptr = (unsigned int)s->mmuEntry + address - MMU_TLB; + *(int*)ptr = value; + s->irqStatus &= ~IRQ_MMU; + return; + } + + ptr = (unsigned int)s->mem + (address % MEM_SIZE); + + if(0x10000000 <= address && address < 0x10000000 + 1024*1024) + ptr += 1024*1024; + + switch(size) + { + case 4: + assert((address & 3) == 0); + if(s->big_endian) + value = htonl(value); + *(int*)ptr = value; + break; + case 2: + assert((address & 1) == 0); + if(s->big_endian) + value = htons((unsigned short)value); + *(short*)ptr = (unsigned short)value; + break; + case 1: + *(char*)ptr = (unsigned char)value; + break; + default: + printf("ERROR"); + } +} + +#ifdef ENABLE_CACHE +/************* Optional MMU and cache implementation *************/ +/* TAG = VirtualAddress | ProcessId | WriteableBit */ +unsigned int mmu_lookup(State *s, unsigned int processId, + unsigned int address, int write) +{ + int i; + unsigned int compare, tag; + + if(processId == 0 || s->userMode == 0) + return address; + //if(address < 0x30000000) + // return address; + compare = (address & ~MMU_MASK) | (processId << 1); + for(i = 0; i < MMU_ENTRIES; ++i) + { + tag = s->mmuEntry[i].virtualAddress; + if((tag & ~1) == compare && (write == 0 || (tag & 1))) + return s->mmuEntry[i].physicalAddress | (address & MMU_MASK); + } + //printf("\nMMUTlbMiss 0x%x PC=0x%x w=%d pid=%d user=%d\n", + // address, s->pc, write, processId, s->userMode); + //printf("m"); + s->exceptionId = 1; + s->faultAddr = address & ~MMU_MASK; + s->irqStatus |= IRQ_MMU; + return address; +} + + +#define CACHE_SET_ASSOC_LN2 0 +#define CACHE_SET_ASSOC (1 << CACHE_SET_ASSOC_LN2) +#define CACHE_SIZE_LN2 (13 - CACHE_SET_ASSOC_LN2) //8 KB +#define CACHE_SIZE (1 << CACHE_SIZE_LN2) +#define CACHE_LINE_SIZE_LN2 2 //4 bytes +#define CACHE_LINE_SIZE (1 << CACHE_LINE_SIZE_LN2) + +static int cacheData[CACHE_SET_ASSOC][CACHE_SIZE/sizeof(int)]; +static int cacheAddr[CACHE_SET_ASSOC][CACHE_SIZE/CACHE_LINE_SIZE]; +static int cacheSetNext; +static int cacheMiss, cacheWriteBack, cacheCount; + +static void cache_init(void) +{ + int set, i; + for(set = 0; set < CACHE_SET_ASSOC; ++set) + { + for(i = 0; i < CACHE_SIZE/CACHE_LINE_SIZE; ++i) + cacheAddr[set][i] = 0xffff0000; + } +} + +/* Write-back cache memory tagged by virtual address and processId */ +/* TAG = virtualAddress | processId | dirtyBit */ +static int cache_load(State *s, unsigned int address, int write) +{ + int set, i, pid, miss, offsetAddr, offsetData, offsetMem; + unsigned int addrTagMatch, addrPrevMatch=0; + unsigned int addrPrev; + unsigned int addressPhysical, tag; + + ++cacheCount; + addrTagMatch = address & ~(CACHE_SIZE-1); + offsetAddr = (address & (CACHE_SIZE-1)) >> CACHE_LINE_SIZE_LN2; + + /* Find match */ + miss = 1; + for(set = 0; set < CACHE_SET_ASSOC; ++set) + { + addrPrevMatch = cacheAddr[set][offsetAddr] & ~(CACHE_SIZE-1); + if(addrPrevMatch == addrTagMatch) + { + miss = 0; + break; + } + } + + /* Cache miss? */ + if(miss) + { + ++cacheMiss; + set = cacheSetNext; + cacheSetNext = (cacheSetNext + 1) & (CACHE_SET_ASSOC-1); + } + //else if(write || (address >> 28) != 0x1) + //{ + // tag = cacheAddr[set][offsetAddr]; + // pid = (tag & (CACHE_SIZE-1)) >> 1; + // if(pid != s->processId) + // miss = 1; + //} + + if(miss) + { + offsetData = address & (CACHE_SIZE-1) & ~(CACHE_LINE_SIZE-1); + + /* Cache line dirty? */ + if(cacheAddr[set][offsetAddr] & 1) + { + /* Write back cache line */ + tag = cacheAddr[set][offsetAddr]; + addrPrev = tag & ~(CACHE_SIZE-1); + addrPrev |= address & (CACHE_SIZE-1); + pid = (tag & (CACHE_SIZE-1)) >> 1; + addressPhysical = mmu_lookup(s, pid, addrPrev, 1); //virtual->physical + if(s->exceptionId) + return 0; + offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1); + for(i = 0; i < CACHE_LINE_SIZE; i += 4) + mem_write(s, 4, offsetMem + i, cacheData[set][(offsetData + i) >> 2]); + ++cacheWriteBack; + } + + /* Read cache line */ + addressPhysical = mmu_lookup(s, s->processId, address, write); //virtual->physical + if(s->exceptionId) + return 0; + offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1); + cacheAddr[set][offsetAddr] = addrTagMatch; + for(i = 0; i < CACHE_LINE_SIZE; i += 4) + cacheData[set][(offsetData + i) >> 2] = mem_read(s, 4, offsetMem + i); + } + cacheAddr[set][offsetAddr] |= write; + return set; +} + +static int cache_read(State *s, int size, unsigned int address) +{ + int set, offset; + int value; + + if((address & 0xfe000000) != 0x10000000) + return mem_read(s, size, address); + + set = cache_load(s, address, 0); + if(s->exceptionId) + return 0; + offset = (address & (CACHE_SIZE-1)) >> 2; + value = cacheData[set][offset]; + if(s->big_endian) + address ^= 3; + switch(size) + { + case 2: + value = (value >> ((address & 2) << 3)) & 0xffff; + break; + case 1: + value = (value >> ((address & 3) << 3)) & 0xff; + break; + } + return value; +} + +static void cache_write(State *s, int size, int unsigned address, unsigned int value) +{ + int set, offset; + unsigned int mask; + + if((address >> 28) != 0x1) // && (s->processId == 0 || s->userMode == 0)) + { + mem_write(s, size, address, value); + return; + } + + set = cache_load(s, address, 1); + if(s->exceptionId) + return; + offset = (address & (CACHE_SIZE-1)) >> 2; + if(s->big_endian) + address ^= 3; + switch(size) + { + case 2: + value &= 0xffff; + value |= value << 16; + mask = 0xffff << ((address & 2) << 3); + break; + case 1: + value &= 0xff; + value |= (value << 8) | (value << 16) | (value << 24); + mask = 0xff << ((address & 3) << 3); + break; + case 4: + default: + mask = 0xffffffff; + break; + } + cacheData[set][offset] = (value & mask) | (cacheData[set][offset] & ~mask); +} + +#define mem_read cache_read +#define mem_write cache_write + +#else +static void cache_init(void) {} +#endif + + +#ifdef SIMPLE_CACHE + +//Write through direct mapped 4KB cache +#define CACHE_MISS 0x1ff +static unsigned int cacheData[1024]; +static unsigned int cacheAddr[1024]; //9-bit addresses +static int cacheTry, cacheMiss, cacheInit; + +static int cache_read(State *s, int size, unsigned int address) +{ + int offset; + unsigned int value, value2, address2=address; + + if(cacheInit == 0) + { + cacheInit = 1; + for(offset = 0; offset < 1024; ++offset) + cacheAddr[offset] = CACHE_MISS; + } + + offset = address >> 20; + if(offset != 0x100 && offset != 0x101) + return mem_read(s, size, address); + + ++cacheTry; + offset = (address >> 2) & 0x3ff; + if(cacheAddr[offset] != (address >> 12) || cacheAddr[offset] == CACHE_MISS) + { + ++cacheMiss; + cacheAddr[offset] = address >> 12; + cacheData[offset] = mem_read(s, 4, address & ~3); + } + value = cacheData[offset]; + if(s->big_endian) + address ^= 3; + switch(size) + { + case 2: + value = (value >> ((address & 2) << 3)) & 0xffff; + break; + case 1: + value = (value >> ((address & 3) << 3)) & 0xff; + break; + } + + //Debug testing + value2 = mem_read(s, size, address2); + if(value != value2) + printf("miss match\n"); + //if((cacheTry & 0xffff) == 0) printf("\n***cache(%d,%d)\n ", cacheMiss, cacheTry); + return value; +} + +static void cache_write(State *s, int size, int unsigned address, unsigned int value) +{ + int offset; + + mem_write(s, size, address, value); + + offset = address >> 20; + if(offset != 0x100 && offset != 0x101) + return; + + offset = (address >> 2) & 0x3ff; + if(size != 4) + { + cacheAddr[offset] = CACHE_MISS; + return; + } + cacheAddr[offset] = address >> 12; + cacheData[offset] = value; +} + +#define mem_read cache_read +#define mem_write cache_write +#endif //SIMPLE_CACHE +/************* End optional cache implementation *************/ + + +void mult_big(unsigned int a, + unsigned int b, + unsigned int *hi, + unsigned int *lo) +{ + unsigned int ahi, alo, bhi, blo; + unsigned int c0, c1, c2; + unsigned int c1_a, c1_b; + + ahi = a >> 16; + alo = a & 0xffff; + bhi = b >> 16; + blo = b & 0xffff; + + c0 = alo * blo; + c1_a = ahi * blo; + c1_b = alo * bhi; + c2 = ahi * bhi; + + c2 += (c1_a >> 16) + (c1_b >> 16); + c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16); + c2 += (c1 >> 16); + c0 = (c1 << 16) + (c0 & 0xffff); + *hi = c2; + *lo = c0; +} + +void mult_big_signed(int a, + int b, + unsigned int *hi, + unsigned int *lo) +{ + unsigned int ahi, alo, bhi, blo; + unsigned int c0, c1, c2; + int c1_a, c1_b; + + ahi = a >> 16; + alo = a & 0xffff; + bhi = b >> 16; + blo = b & 0xffff; + + c0 = alo * blo; + c1_a = ahi * blo; + c1_b = alo * bhi; + c2 = ahi * bhi; + + c2 += (c1_a >> 16) + (c1_b >> 16); + c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16); + c2 += (c1 >> 16); + c0 = (c1 << 16) + (c0 & 0xffff); + *hi = c2; + *lo = c0; +} + +//execute one cycle of a Plasma CPU +void cycle(State *s, int show_mode) +{ + unsigned int opcode; + unsigned int op, rs, rt, rd, re, func, imm, target; + int imm_shift, branch=0, lbranch=2, skip2=0; + int *r=s->r; + unsigned int *u=(unsigned int*)s->r; + unsigned int ptr, epc, rSave; + + opcode = mem_read(s, 4, s->pc); + op = (opcode >> 26) & 0x3f; + rs = (opcode >> 21) & 0x1f; + rt = (opcode >> 16) & 0x1f; + rd = (opcode >> 11) & 0x1f; + re = (opcode >> 6) & 0x1f; + func = opcode & 0x3f; + imm = opcode & 0xffff; + imm_shift = (((int)(short)imm) << 2) - 4; + target = (opcode << 6) >> 4; + ptr = (short)imm + r[rs]; + r[0] = 0; + if(show_mode) + { + printf("%8.8x %8.8x ", s->pc, opcode); + if(op == 0) + printf("%8s ", special_string[func]); + else if(op == 1) + printf("%8s ", regimm_string[rt]); + else + printf("%8s ", opcode_string[op]); + printf("$%2.2d $%2.2d $%2.2d $%2.2d ", rs, rt, rd, re); + printf("%4.4x", imm); + if(show_mode == 1) + printf(" r[%2.2d]=%8.8x r[%2.2d]=%8.8x", rs, r[rs], rt, r[rt]); + printf("\n"); + } + if(show_mode > 5) + return; + epc = s->pc + 4; + if(s->pc_next != s->pc + 4) + epc |= 2; //branch delay slot + s->pc = s->pc_next; + s->pc_next = s->pc_next + 4; + if(s->skip) + { + s->skip = 0; + return; + } + rSave = r[rt]; + switch(op) + { + case 0x00:/*SPECIAL*/ + switch(func) + { + case 0x00:/*SLL*/ r[rd]=r[rt]<>re; break; + case 0x03:/*SRA*/ r[rd]=r[rt]>>re; break; + case 0x04:/*SLLV*/ r[rd]=r[rt]<>r[rs]; break; + case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs]; break; + case 0x08:/*JR*/ s->pc_next=r[rs]; break; + case 0x09:/*JALR*/ r[rd]=s->pc_next; s->pc_next=r[rs]; break; + case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs]; break; /*IV*/ + case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs]; break; /*IV*/ + case 0x0c:/*SYSCALL*/ epc|=1; s->exceptionId=1; break; + case 0x0d:/*BREAK*/ epc|=1; s->exceptionId=1; break; + case 0x0f:/*SYNC*/ s->wakeup=1; break; + case 0x10:/*MFHI*/ r[rd]=s->hi; break; + case 0x11:/*FTHI*/ s->hi=r[rs]; break; + case 0x12:/*MFLO*/ r[rd]=s->lo; break; + case 0x13:/*MTLO*/ s->lo=r[rs]; break; + case 0x18:/*MULT*/ mult_big_signed(r[rs],r[rt],&s->hi,&s->lo); break; + case 0x19:/*MULTU*/ mult_big(r[rs],r[rt],&s->hi,&s->lo); break; + case 0x1a:/*DIV*/ s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break; + case 0x1b:/*DIVU*/ s->lo=u[rs]/u[rt]; s->hi=u[rs]%u[rt]; break; + case 0x20:/*ADD*/ r[rd]=r[rs]+r[rt]; break; + case 0x21:/*ADDU*/ r[rd]=r[rs]+r[rt]; break; + case 0x22:/*SUB*/ r[rd]=r[rs]-r[rt]; break; + case 0x23:/*SUBU*/ r[rd]=r[rs]-r[rt]; break; + case 0x24:/*AND*/ r[rd]=r[rs]&r[rt]; break; + case 0x25:/*OR*/ r[rd]=r[rs]|r[rt]; break; + case 0x26:/*XOR*/ r[rd]=r[rs]^r[rt]; break; + case 0x27:/*NOR*/ r[rd]=~(r[rs]|r[rt]); break; + case 0x2a:/*SLT*/ r[rd]=r[rs]pc, opcode); + s->wakeup=1; + } + break; + case 0x01:/*REGIMM*/ + switch(rt) { + case 0x10:/*BLTZAL*/ r[31]=s->pc_next; + case 0x00:/*BLTZ*/ branch=r[rs]<0; break; + case 0x11:/*BGEZAL*/ r[31]=s->pc_next; + case 0x01:/*BGEZ*/ branch=r[rs]>=0; break; + case 0x12:/*BLTZALL*/r[31]=s->pc_next; + case 0x02:/*BLTZL*/ lbranch=r[rs]<0; break; + case 0x13:/*BGEZALL*/r[31]=s->pc_next; + case 0x03:/*BGEZL*/ lbranch=r[rs]>=0; break; + default: printf("ERROR1\n"); s->wakeup=1; + } + break; + case 0x03:/*JAL*/ r[31]=s->pc_next; + case 0x02:/*J*/ s->pc_next=(s->pc&0xf0000000)|target; break; + case 0x04:/*BEQ*/ branch=r[rs]==r[rt]; break; + case 0x05:/*BNE*/ branch=r[rs]!=r[rt]; break; + case 0x06:/*BLEZ*/ branch=r[rs]<=0; break; + case 0x07:/*BGTZ*/ branch=r[rs]>0; break; + case 0x08:/*ADDI*/ r[rt]=r[rs]+(short)imm; break; + case 0x09:/*ADDIU*/ u[rt]=u[rs]+(short)imm; break; + case 0x0a:/*SLTI*/ r[rt]=r[rs]<(short)imm; break; + case 0x0b:/*SLTIU*/ u[rt]=u[rs]<(unsigned int)(short)imm; break; + case 0x0c:/*ANDI*/ r[rt]=r[rs]&imm; break; + case 0x0d:/*ORI*/ r[rt]=r[rs]|imm; break; + case 0x0e:/*XORI*/ r[rt]=r[rs]^imm; break; + case 0x0f:/*LUI*/ r[rt]=(imm<<16); break; + case 0x10:/*COP0*/ + if((opcode & (1<<23)) == 0) //move from CP0 + { + if(rd == 12) + r[rt]=s->status; + else + r[rt]=s->epc; + } + else //move to CP0 + { + s->status=r[rt]&1; + if(s->processId && (r[rt]&2)) + { + s->userMode|=r[rt]&2; + //printf("CpuStatus=%d %d %d\n", r[rt], s->status, s->userMode); + //s->wakeup = 1; + //printf("pc=0x%x\n", epc); + } + } + break; +// case 0x11:/*COP1*/ break; +// case 0x12:/*COP2*/ break; +// case 0x13:/*COP3*/ break; + case 0x14:/*BEQL*/ lbranch=r[rs]==r[rt]; break; + case 0x15:/*BNEL*/ lbranch=r[rs]!=r[rt]; break; + case 0x16:/*BLEZL*/ lbranch=r[rs]<=0; break; + case 0x17:/*BGTZL*/ lbranch=r[rs]>0; break; +// case 0x1c:/*MAD*/ break; /*IV*/ + case 0x20:/*LB*/ r[rt]=(signed char)mem_read(s,1,ptr); break; + case 0x21:/*LH*/ r[rt]=(signed short)mem_read(s,2,ptr); break; + case 0x22:/*LWL*/ + //target=8*(ptr&3); + //r[rt]=(r[rt]&~(0xffffffff<>target))| + //((unsigned int)mem_read(s,4,ptr&~3)>>target); + break; + case 0x28:/*SB*/ mem_write(s,1,ptr,r[rt]); break; + case 0x29:/*SH*/ mem_write(s,2,ptr,r[rt]); break; + case 0x2a:/*SWL*/ + //mem_write(s,1,ptr,r[rt]>>24); + //mem_write(s,1,ptr+1,r[rt]>>16); + //mem_write(s,1,ptr+2,r[rt]>>8); + //mem_write(s,1,ptr+3,r[rt]); break; + case 0x2b:/*SW*/ mem_write(s,4,ptr,r[rt]); break; + case 0x2e:/*SWR*/ break; //fixme + case 0x2f:/*CACHE*/break; + case 0x30:/*LL*/ r[rt]=mem_read(s,4,ptr); break; +// case 0x31:/*LWC1*/ break; +// case 0x32:/*LWC2*/ break; +// case 0x33:/*LWC3*/ break; +// case 0x35:/*LDC1*/ break; +// case 0x36:/*LDC2*/ break; +// case 0x37:/*LDC3*/ break; +// case 0x38:/*SC*/ *(int*)ptr=r[rt]; r[rt]=1; break; + case 0x38:/*SC*/ mem_write(s,4,ptr,r[rt]); r[rt]=1; break; +// case 0x39:/*SWC1*/ break; +// case 0x3a:/*SWC2*/ break; +// case 0x3b:/*SWC3*/ break; +// case 0x3d:/*SDC1*/ break; +// case 0x3e:/*SDC2*/ break; +// case 0x3f:/*SDC3*/ break; + default: printf("ERROR2 address=0x%x opcode=0x%x\n", s->pc, opcode); + s->wakeup=1; + } + s->pc_next += (branch || lbranch == 1) ? imm_shift : 0; + s->pc_next &= ~3; + s->skip = (lbranch == 0) | skip2; + + if(s->exceptionId) + { + r[rt] = rSave; + s->epc = epc; + s->pc_next = 0x3c; + s->skip = 1; + s->exceptionId = 0; + s->userMode = 0; + //s->wakeup = 1; + return; + } +} + +void show_state(State *s) +{ + int i,j; + printf("pid=%d userMode=%d, epc=0x%x\n", s->processId, s->userMode, s->epc); + for(i = 0; i < 4; ++i) + { + printf("%2.2d ", i * 8); + for(j = 0; j < 8; ++j) + { + printf("%8.8x ", s->r[i*8+j]); + } + printf("\n"); + } + //printf("%8.8lx %8.8lx %8.8lx %8.8lx\n", s->pc, s->pc_next, s->hi, s->lo); + j = s->pc; + for(i = -4; i <= 8; ++i) + { + printf("%c", i==0 ? '*' : ' '); + s->pc = j + i * 4; + cycle(s, 10); + } + s->pc = j; +} + +void do_debug(State *s) +{ + int ch; + int i, j=0, watch=0, addr; + s->pc_next = s->pc + 4; + s->skip = 0; + s->wakeup = 0; + show_state(s); + ch = ' '; + for(;;) + { + if(ch != 'n') + { + if(watch) + printf("0x%8.8x=0x%8.8x\n", watch, mem_read(s, 4, watch)); + printf("1=Debug 2=Trace 3=Step 4=BreakPt 5=Go 6=Memory "); + printf("7=Watch 8=Jump 9=Quit> "); + } + ch = getch(); + if(ch != 'n') + printf("\n"); + switch(ch) + { + case '1': case 'd': case ' ': + cycle(s, 0); show_state(s); break; + case 'n': + cycle(s, 1); break; + case '2': case 't': + cycle(s, 0); printf("*"); cycle(s, 10); break; + case '3': case 's': + printf("Count> "); + scanf("%d", &j); + for(i = 0; i < j; ++i) + cycle(s, 1); + show_state(s); + break; + case '4': case 'b': + printf("Line> "); + scanf("%x", &j); + printf("break point=0x%x\n", j); + break; + case '5': case 'g': + s->wakeup = 0; + cycle(s, 0); + while(s->wakeup == 0) + { + if(s->pc == j) + break; + cycle(s, 0); + } + show_state(s); + break; + case 'G': + s->wakeup = 0; + cycle(s, 1); + while(s->wakeup == 0) + { + if(s->pc == j) + break; + cycle(s, 1); + } + show_state(s); + break; + case '6': case 'm': + printf("Memory> "); + scanf("%x", &j); + for(i = 0; i < 8; ++i) + { + printf("%8.8x ", mem_read(s, 4, j+i*4)); + } + printf("\n"); + break; + case '7': case 'w': + printf("Watch> "); + scanf("%x", &watch); + break; + case '8': case 'j': + printf("Jump> "); + scanf("%x", &addr); + s->pc = addr; + s->pc_next = addr + 4; + show_state(s); + break; + case '9': case 'q': + return; + } + } +} +/************************************************************/ + +int main(int argc,char *argv[]) +{ + State state, *s=&state; + FILE *in; + int bytes, index; + printf("Plasma emulator\n"); + memset(s, 0, sizeof(State)); + s->big_endian = 1; + s->mem = (unsigned char*)malloc(MEM_SIZE); + memset(s->mem, 0, MEM_SIZE); + if(argc <= 1) + { + printf(" Usage: mlite file.exe\n"); + printf(" mlite file.exe B {for big_endian}\n"); + printf(" mlite file.exe L {for little_endian}\n"); + printf(" mlite file.exe BD {disassemble big_endian}\n"); + printf(" mlite file.exe LD {disassemble little_endian}\n"); + + return 0; + } + in = fopen(argv[1], "rb"); + if(in == NULL) + { + printf("Can't open file %s!\n",argv[1]); + getch(); + return(0); + } + bytes = fread(s->mem, 1, MEM_SIZE, in); + fclose(in); + memcpy(s->mem + 1024*1024, s->mem, 1024*1024); //internal 8KB SRAM + printf("Read %d bytes.\n", bytes); + cache_init(); + if(argc == 3 && argv[2][0] == 'B') + { + printf("Big Endian\n"); + s->big_endian = 1; + } + if(argc == 3 && argv[2][0] == 'L') + { + printf("Big Endian\n"); + s->big_endian = 0; + } + s->processId = 0; + if(argc == 3 && argv[2][0] == 'S') + { /*make big endian*/ + printf("Big Endian\n"); + for(index = 0; index < bytes+3; index += 4) + { + *(unsigned int*)&s->mem[index] = htonl(*(unsigned int*)&s->mem[index]); + } + in = fopen("big.exe", "wb"); + fwrite(s->mem, bytes, 1, in); + fclose(in); + return(0); + } + if(argc == 3 && argv[2][1] == 'D') + { /*dump image*/ + for(index = 0; index < bytes; index += 4) { + s->pc = index; + cycle(s, 10); + } + free(s->mem); + return(0); + } + s->pc = 0x0; + index = mem_read(s, 4, 0); + if((index & 0xffffff00) == 0x3c1c1000) + s->pc = 0x10000000; + do_debug(s); + free(s->mem); + return(0); +} + diff --git a/tools/no_os.c b/tools/no_os.c new file mode 100644 index 0000000..07dd9bd --- /dev/null +++ b/tools/no_os.c @@ -0,0 +1,54 @@ +#include "plasma.h" + +#define MemoryRead(A) (*(volatile unsigned int*)(A)) +#define MemoryWrite(A,V) *(volatile unsigned int*)(A)=(V) + +int putchar(int value) +{ + while((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) == 0) + ; + MemoryWrite(UART_WRITE, value); + return 0; +} + +int puts(const char *string) +{ + while(*string) + { + if(*string == '\n') + putchar('\r'); + putchar(*string++); + } + return 0; +} + +void print_hex(unsigned long num) +{ + long i; + unsigned long j; + for(i = 28; i >= 0; i -= 4) + { + j = (num >> i) & 0xf; + if(j < 10) + putchar('0' + j); + else + putchar('a' - 10 + j); + } +} + +void OS_InterruptServiceRoutine(unsigned int status) +{ + (void)status; + putchar('I'); +} + +int kbhit(void) +{ + return MemoryRead(IRQ_STATUS) & IRQ_UART_READ_AVAILABLE; +} + +int getch(void) +{ + while(!kbhit()) ; + return MemoryRead(UART_READ); +} diff --git a/tools/opcodes.asm b/tools/opcodes.asm new file mode 100644 index 0000000..1482219 --- /dev/null +++ b/tools/opcodes.asm @@ -0,0 +1,1108 @@ +################################################################## +# TITLE: Opcode Tester +# AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +# DATE CREATED: 1/10/02 +# FILENAME: opcodes.asm +# PROJECT: Plasma CPU core +# COPYRIGHT: Software placed into the public domain by the author. +# Software 'as is' without warranty. Author liable for nothing. +# DESCRIPTION: +# This assembly file tests all of the opcodes supported by the +# Plasma core. +# This test assumes that address 0x20000000 is the UART write register +# Successful tests will print out "A" or "AB" or "ABC" or .... +# Missing letters or letters out of order indicate a failure. +################################################################## + .text + .align 2 + .globl entry + .ent entry +entry: + .set noreorder + + la $gp, _gp #initialize stack pointer + la $4, __bss_start #$4 = .sbss_start + la $5, _end #$5 = .bss_end + nop #no stack needed + nop + + b StartTest + nop #nops required to place ISR at 0x3c + nop + +OS_AsmPatchValue: + #Code to place at address 0x3c + lui $26, 0x1000 + ori $26, $26, 0x3c + jr $26 + nop + +InterruptVector: #Address=0x3c + mfc0 $26,$14 #C0_EPC=14 (Exception PC) + jr $26 + add $4,$4,5 + +StartTest: + mtc0 $0,$12 #disable interrupts + lui $20,0x2000 #serial port write address + ori $21,$0,'\n' # letter + ori $22,$0,'X' #'X' letter + ori $23,$0,'\r' + ori $24,$0,0x0f80 #temp memory + + sb $23,0($20) + sb $21,0($20) + sb $23,0($20) + sb $21,0($20) + sb $23,0($20) + sb $21,0($20) + sb $23,0($20) + sb $21,0($20) + + #Patch interrupt vector to 0x1000003c + la $5, OS_AsmPatchValue + sub $6,$5,0x1000 + blez $6,NoPatch + + lw $6, 0($5) + sw $6, 0x3c($0) + lw $6, 4($5) + sw $6, 0x40($0) + lw $6, 8($5) + sw $6, 0x44($0) + lw $6, 12($5) + sw $6, 0x48($0) +NoPatch: + + ###################################### + #Arithmetic Instructions + ###################################### +ArthmeticTest: + ori $2,$0,'A' + sb $2,0($20) + ori $2,$0,'r' + sb $2,0($20) + ori $2,$0,'i' + sb $2,0($20) + ori $2,$0,'t' + sb $2,0($20) + ori $2,$0,'h' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #a: ADD + ori $2,$0,'a' + sb $2,0($20) + ori $3,$0,5 + ori $4,$0,60 + add $2,$3,$4 + sb $2,0($20) #A + sb $23,0($20) + sb $21,0($20) + + #b: ADDI + ori $2,$0,'b' + sb $2,0($20) + ori $4,$0,60 + addi $2,$4,5 + sb $2,0($20) #A + sb $23,0($20) + sb $21,0($20) + + #c: ADDIU + ori $2,$0,'c' + sb $2,0($20) + ori $4,$0,50 + addiu $5,$4,15 + sb $5,0($20) #A + sb $23,0($20) + sb $21,0($20) + + #d: ADDU + ori $2,$0,'d' + sb $2,0($20) + ori $3,$0,5 + ori $4,$0,60 + add $2,$3,$4 + sb $2,0($20) #A + sb $23,0($20) + sb $21,0($20) + + #e: DIV + ori $2,$0,'e' + sb $2,0($20) + ori $2,$0,65*117+41 + ori $3,$0,117 + div $2,$3 + nop + mflo $4 + sb $4,0($20) #A + mfhi $4 + addi $4,$4,66-41 + sb $4,0($20) #B + li $2,-67*19 + ori $3,$0,19 + div $2,$3 + nop + mflo $4 + sub $4,$0,$4 + sb $4,0($20) #C + ori $2,$0,68*23 + li $3,-23 + div $2,$3 + nop + mflo $4 + sub $4,$0,$4 + sb $4,0($20) #D + li $2,-69*13 + li $3,-13 + div $2,$3 + mflo $4 + sb $4,0($20) #E + sb $23,0($20) + sb $21,0($20) + + #f: DIVU + ori $2,$0,'f' + sb $2,0($20) + ori $2,$0,65*13 + ori $3,$0,13 + divu $2,$3 + nop + mflo $4 + sb $4,0($20) #A + sb $23,0($20) + sb $21,0($20) + + #g: MULT + ori $2,$0,'g' + sb $2,0($20) + ori $2,$0,5 + ori $3,$0,13 + mult $2,$3 + nop + mflo $4 + sb $4,0($20) #A + li $2,-5 + ori $3,$0,13 + mult $2,$3 + mfhi $5 + mflo $4 + sub $4,$0,$4 + addu $4,$4,$5 + addi $4,$4,2 + sb $4,0($20) #B + ori $2,$0,5 + li $3,-13 + mult $2,$3 + mfhi $5 + mflo $4 + sub $4,$0,$4 + addu $4,$4,$5 + addi $4,$4,3 + sb $4,0($20) #C + li $2,-5 + li $3,-13 + mult $2,$3 + mfhi $5 + mflo $4 + addu $4,$4,$5 + addi $4,$4,3 + sb $4,0($20) #D + lui $4,0xfe98 + ori $4,$4,0x62e5 + lui $5,0x6 + ori $5,0x8db8 + mult $4,$5 + mfhi $6 + addiu $7,$6,2356+1+'E' #E + sb $7,0($20) + sb $23,0($20) + sb $21,0($20) + + #h: MULTU + ori $2,$0,'h' + sb $2,0($20) + ori $2,$0,5 + ori $3,$0,13 + multu $2,$3 + nop + mflo $4 + sb $4,0($20) #A + sb $23,0($20) + sb $21,0($20) + + #i: SLT + ori $2,$0,'i' + sb $2,0($20) + ori $2,$0,10 + ori $3,$0,12 + slt $4,$2,$3 + addi $5,$4,64 + sb $5,0($20) #A + slt $4,$3,$2 + addi $5,$4,66 + sb $5,0($20) #B + li $2,0xfffffff0 + slt $4,$2,$3 + addi $5,$4,66 + sb $5,0($20) #C + slt $4,$3,$2 + addi $5,$4,68 + sb $5,0($20) #D + li $3,0xffffffff + slt $4,$2,$3 + addi $5,$4,68 + sb $5,0($20) #E + slt $4,$3,$2 + addi $5,$4,70 + sb $5,0($20) #F + sb $23,0($20) + sb $21,0($20) + + #j: SLTI + ori $2,$0,'j' + sb $2,0($20) + ori $2,$0,10 + slti $4,$2,12 + addi $5,$4,64 + sb $5,0($20) #A + slti $4,$2,8 + addi $5,$4,66 + sb $5,0($20) #B + sb $23,0($20) + sb $21,0($20) + + #k: SLTIU + ori $2,$0,'k' + sb $2,0($20) + ori $2,$0,10 + sltiu $4,$2,12 + addi $5,$4,64 + sb $5,0($20) #A + sltiu $4,$2,8 + addi $5,$4,66 + sb $5,0($20) #B + sb $23,0($20) + sb $21,0($20) + + #l: SLTU + ori $2,$0,'l' + sb $2,0($20) + ori $2,$0,10 + ori $3,$0,12 + slt $4,$2,$3 + addi $5,$4,64 + sb $5,0($20) #A + slt $4,$3,$2 + addi $5,$4,66 + sb $5,0($20) #B + sb $23,0($20) + sb $21,0($20) + + #m: SUB + ori $2,$0,'m' + sb $2,0($20) + ori $3,$0,70 + ori $4,$0,5 + sub $2,$3,$4 + sb $2,0($20) #A + sb $23,0($20) + sb $21,0($20) + + #n: SUBU + ori $2,$0,'n' + sb $2,0($20) + ori $3,$0,70 + ori $4,$0,5 + sub $2,$3,$4 + sb $2,0($20) #A + sb $23,0($20) + sb $21,0($20) + + ###################################### + #Branch and Jump Instructions + ###################################### +BranchTest: + ori $2,$0,'B' + sb $2,0($20) + ori $2,$0,'r' + sb $2,0($20) + ori $2,$0,'a' + sb $2,0($20) + ori $2,$0,'n' + sb $2,0($20) + ori $2,$0,'c' + sb $2,0($20) + ori $2,$0,'h' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #a: B + ori $2,$0,'a' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + b $B1 + sb $10,0($20) + sb $22,0($20) +$B1: + sb $11,0($20) + sb $23,0($20) + sb $21,0($20) + + #b: BAL + ori $2,$0,'b' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $14,$0,'E' + ori $15,$0,'X' + bal $BAL1 + sb $10,0($20) + sb $13,0($20) + b $BAL2 + sb $14,0($20) + sb $15,0($20) +$BAL1: + sb $11,0($20) + jr $31 + sb $12,0($20) + sb $22,0($20) +$BAL2: + sb $23,0($20) + sb $21,0($20) + + #c: BEQ + ori $2,$0,'c' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $2,$0,100 + ori $3,$0,123 + ori $4,$0,123 + beq $2,$3,$BEQ1 + sb $10,0($20) + sb $11,0($20) + beq $3,$4,$BEQ1 + sb $12,0($20) + sb $22,0($20) +$BEQ1: + sb $13,0($20) + sb $23,0($20) + sb $21,0($20) + + #d: BGEZ + ori $2,$0,'d' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + or $15,$0,'X' + ori $2,$0,100 + li $3,0xffff1234 + ori $4,$0,123 + bgez $3,$BGEZ1 + sb $10,0($20) + sb $11,0($20) + bgez $2,$BGEZ1 + sb $12,0($20) + sb $22,0($20) +$BGEZ1: + bgez $0,$BGEZ2 + nop + sb $15,0($20) +$BGEZ2: + sb $13,0($20) + sb $23,0($20) + sb $21,0($20) + + #e: BGEZAL + ori $2,$0,'e' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $14,$0,'E' + ori $15,$0,'X' + li $3,0xffff1234 + bgezal $3,$BGEZAL1 + nop + sb $10,0($20) + bgezal $0,$BGEZAL1 + nop + sb $13,0($20) + b $BGEZAL2 + sb $14,0($20) + sb $15,0($20) +$BGEZAL1: + sb $11,0($20) + jr $31 + sb $12,0($20) + sb $22,0($20) +$BGEZAL2: + sb $23,0($20) + sb $21,0($20) + + #f: BGTZ + ori $2,$0,'f' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $2,$0,100 + li $3,0xffff1234 + bgtz $3,$BGTZ1 + sb $10,0($20) + sb $11,0($20) + bgtz $2,$BGTZ1 + sb $12,0($20) + sb $22,0($20) +$BGTZ1: + sb $13,0($20) + sb $23,0($20) + sb $21,0($20) + + #g: BLEZ + ori $2,$0,'g' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $2,$0,100 + li $3,0xffff1234 + blez $2,$BLEZ1 + sb $10,0($20) + sb $11,0($20) + blez $3,$BLEZ1 + sb $12,0($20) + sb $22,0($20) +$BLEZ1: + blez $0,$BLEZ2 + nop + sb $22,0($20) +$BLEZ2: + sb $13,0($20) + sb $23,0($20) + sb $21,0($20) + + #h: BLTZ + ori $2,$0,'h' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $14,$0,'E' + ori $2,$0,100 + li $3,0xffff1234 + ori $4,$0,0 + bltz $2,$BLTZ1 + sb $10,0($20) + sb $11,0($20) + bltz $3,$BLTZ1 + sb $12,0($20) + sb $22,0($20) +$BLTZ1: + bltz $4,$BLTZ2 + nop + sb $13,0($20) +$BLTZ2: + sb $14,0($20) + sb $23,0($20) + sb $21,0($20) + + #i: BLTZAL + ori $2,$0,'i' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $14,$0,'E' + ori $15,$0,'X' + li $3,0xffff1234 + bltzal $0,$BLTZAL1 + nop + sb $10,0($20) + bltzal $3,$BLTZAL1 + nop + sb $13,0($20) + b $BLTZAL2 + sb $14,0($20) + sb $15,0($20) +$BLTZAL1: + sb $11,0($20) + jr $31 + sb $12,0($20) + sb $22,0($20) +$BLTZAL2: + sb $23,0($20) + sb $21,0($20) + + #j: BNE + ori $2,$0,'j' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $2,$0,100 + ori $3,$0,123 + ori $4,$0,123 + bne $3,$4,$BNE1 + sb $10,0($20) + sb $11,0($20) + bne $2,$3,$BNE1 + sb $12,0($20) + sb $22,0($20) +$BNE1: + sb $13,0($20) + sb $23,0($20) + sb $21,0($20) + + #k: J + ori $2,$0,'k' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $15,$0,'X' + j $J1 + sb $10,0($20) + sb $15,0($20) +$J1: + sb $11,0($20) + sb $23,0($20) + sb $21,0($20) + + #l: JAL + ori $2,$0,'l' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $14,$0,'E' + ori $15,$0,'X' + jal $JAL1 + sb $10,0($20) + sb $13,0($20) + b $JAL2 + sb $14,0($20) + sb $15,0($20) +$JAL1: + sb $11,0($20) + jr $31 + sb $12,0($20) + sb $22,0($20) +$JAL2: + sb $23,0($20) + sb $21,0($20) + + #m: JALR + ori $2,$0,'m' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $12,$0,'C' + ori $13,$0,'D' + ori $14,$0,'E' + ori $15,$0,'X' + la $3,$JALR1 + jalr $3 + sb $10,0($20) + sb $13,0($20) + b $JALR2 + sb $14,0($20) + sb $15,0($20) +$JALR1: + sb $11,0($20) + jr $31 + sb $12,0($20) + sb $22,0($20) +$JALR2: + sb $23,0($20) + sb $21,0($20) + + #n: JR + ori $2,$0,'n' + sb $2,0($20) + ori $10,$0,'A' + ori $11,$0,'B' + ori $15,$0,'X' + la $3,$JR1 + jr $3 + sb $10,0($20) + sb $15,0($20) +$JR1: + sb $11,0($20) + sb $23,0($20) + sb $21,0($20) + + #o: NOP + ori $2,$0,'o' + sb $2,0($20) + ori $2,$0,65 + nop + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + +# b LoadTest + +BreakTest: + #p: BREAK + ori $2,$0,'p' + sb $2,0($20) + ori $2,$0,'z' + ori $4,$0,59 + break 0 + addi $4,$4,1 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + #q: SYSCALL + ori $2,$0,'q' + sb $2,0($20) + ori $4,$0,61 + syscall 0 + addi $4,$4,-1 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + + ###################################### + #Load, Store, and Memory Control Instructions + ###################################### +LoadTest: + ori $2,$0,'L' + sb $2,0($20) + ori $2,$0,'o' + sb $2,0($20) + ori $2,$0,'a' + sb $2,0($20) + ori $2,$0,'d' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #a: LB + ori $2,$0,'a' + sb $2,0($20) + or $2,$0,$24 + li $3,0x414243fc + sw $3,16($2) + lb $4,16($2) + sb $4,0($20) + lb $4,17($2) + sb $4,0($20) + lb $4,18($2) + sb $4,0($20) + lb $2,19($2) + sra $3,$2,8 + addi $3,$3,0x45 + sb $3,0($20) + addi $2,$2,0x49 + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #b: LBU + ori $2,$0,'b' + sb $2,0($20) + or $2,$0,$24 + li $3,0x41424344 + sw $3,16($2) + lb $4,16($2) + sb $4,0($20) + lb $4,17($2) + sb $4,0($20) + lb $4,18($2) + sb $4,0($20) + lb $2,19($2) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #c: LH + ori $2,$0,'c' + sb $2,0($20) + or $2,$0,$24 + li $3,0x00410042 + sw $3,16($2) + lh $4,16($2) + sb $4,0($20) + lh $2,18($2) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #d: LHU + ori $2,$0,'d' + sb $2,0($20) + or $2,$0,$24 + li $3,0x00410042 + sw $3,16($2) + lh $4,16($2) + sb $4,0($20) + lh $2,18($2) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #e: LW + ori $2,$0,'e' + sb $2,0($20) + or $2,$0,$24 + li $3,'A' + sw $3,16($2) + ori $3,$0,0 + lw $2,16($2) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #f: LWL & LWR + ori $2,$0,'f' + sb $2,0($20) + or $2,$0,$24 + li $3,'A' + sw $3,16($2) + ori $3,$0,0 + lwl $2,16($2) + lwr $2,16($2) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #g: SB + ori $2,$0,'g' + sb $2,0($20) + ori $2,$0,'A' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #h: SH + ori $2,$0,'h' + sb $2,0($20) + or $4,$0,$24 + ori $2,$0,0x4142 + sh $2,16($4) + lb $3,16($4) + sb $3,0($20) + lb $2,17($4) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #i: SW + ori $2,$0,'i' + sb $2,0($20) + or $2,$0,$24 + li $3,0x41424344 + sw $3,16($2) + lb $4,16($2) + sb $4,0($20) + lb $4,17($2) + sb $4,0($20) + lb $4,18($2) + sb $4,0($20) + lb $2,19($2) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #j: SWL & SWR + ori $2,$0,'j' + sb $2,0($20) + or $2,$0,$24 + li $3,0x41424344 + swl $3,16($2) + swr $3,16($2) + lb $4,16($2) + sb $4,0($20) + lb $4,17($2) + sb $4,0($20) + lb $4,18($2) + sb $4,0($20) + lb $2,19($2) + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + + ###################################### + #Logical Instructions + ###################################### +LogicalTest: + ori $2,$0,'L' + sb $2,0($20) + ori $2,$0,'o' + sb $2,0($20) + ori $2,$0,'g' + sb $2,0($20) + ori $2,$0,'i' + sb $2,0($20) + ori $2,$0,'c' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #a: AND + ori $2,$0,'a' + sb $2,0($20) + ori $2,$0,0x0741 + ori $3,$0,0x60f3 + and $4,$2,$3 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + #b: ANDI + ori $2,$0,'b' + sb $2,0($20) + ori $2,$0,0x0741 + andi $4,$2,0x60f3 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + #c: LUI + ori $2,$0,'c' + sb $2,0($20) + lui $2,0x41 + srl $3,$2,16 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #d: NOR + ori $2,$0,'d' + sb $2,0($20) + li $2,0xf0fff08e + li $3,0x0f0f0f30 + nor $4,$2,$3 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + #e: OR + ori $2,$0,'e' + sb $2,0($20) + ori $2,$0,0x40 + ori $3,$0,0x01 + or $4,$2,$3 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + #f: ORI + ori $2,$0,'f' + sb $2,0($20) + ori $2,$0,0x40 + ori $4,$2,0x01 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + #g: XOR + ori $2,$0,'g' + sb $2,0($20) + ori $2,$0,0xf043 + ori $3,$0,0xf002 + xor $4,$2,$3 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + #h: XORI + ori $2,$0,'h' + sb $2,0($20) + ori $2,$0,0xf043 + xor $4,$2,0xf002 + sb $4,0($20) + sb $23,0($20) + sb $21,0($20) + + + ###################################### + #Move Instructions + ###################################### +MoveTest: + ori $2,$0,'M' + sb $2,0($20) + ori $2,$0,'o' + sb $2,0($20) + ori $2,$0,'v' + sb $2,0($20) + ori $2,$0,'e' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #a: MFHI + ori $2,$0,'a' + sb $2,0($20) + ori $2,$0,65 + mthi $2 + mfhi $3 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #b: MFLO + ori $2,$0,'b' + sb $2,0($20) + ori $2,$0,65 + mtlo $2 + mflo $3 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #c: MTHI + ori $2,$0,'c' + sb $2,0($20) + ori $2,$0,65 + mthi $2 + mfhi $3 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #d: MTLO + ori $2,$0,'d' + sb $2,0($20) + ori $2,$0,65 + mtlo $2 + mflo $3 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + + ###################################### + #Shift Instructions + ###################################### +ShiftTest: + ori $2,$0,'S' + sb $2,0($20) + ori $2,$0,'h' + sb $2,0($20) + ori $2,$0,'i' + sb $2,0($20) + ori $2,$0,'f' + sb $2,0($20) + ori $2,$0,'t' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + #a: SLL + ori $2,$0,'a' + sb $2,0($20) + li $2,0x40414243 + sll $3,$2,8 + srl $3,$3,24 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #b: SLLV + ori $2,$0,'b' + sb $2,0($20) + li $2,0x40414243 + ori $3,$0,8 + sllv $3,$2,$3 + srl $3,$3,24 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #c: SRA + ori $2,$0,'c' + sb $2,0($20) + li $2,0x40414243 + sra $3,$2,16 + sb $3,0($20) + li $2,0x84000000 + sra $3,$2,25 + sub $3,$3,0x80 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #d: SRAV + ori $2,$0,'d' + sb $2,0($20) + li $2,0x40414243 + ori $3,$0,16 + srav $3,$2,$3 + sb $3,0($20) + ori $3,$0,25 + li $2,0x84000000 + srav $3,$2,$3 + sub $3,$3,0x80 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #e: SRL + ori $2,$0,'e' + sb $2,0($20) + li $2,0x40414243 + srl $3,$2,16 + sb $3,0($20) + li $2,0x84000000 + srl $3,$2,25 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + #f: SRLV + ori $2,$0,'f' + sb $2,0($20) + li $2,0x40414243 + ori $3,$0,16 + srlv $4,$2,$3 + sb $4,0($20) + ori $3,$0,25 + li $2,0x84000000 + srlv $3,$2,$3 + sb $3,0($20) + sb $23,0($20) + sb $21,0($20) + + + ori $2,$0,'D' + sb $2,0($20) + ori $2,$0,'o' + sb $2,0($20) + ori $2,$0,'n' + sb $2,0($20) + ori $2,$0,'e' + sb $2,0($20) + sb $23,0($20) + sb $21,0($20) + + +$DONE: + j $DONE + nop + + .set reorder + .end entry + diff --git a/tools/output.txt b/tools/output.txt new file mode 100644 index 0000000..bfc4302 --- /dev/null +++ b/tools/output.txt @@ -0,0 +1,43 @@ +12345678 091a2b3c 048d159e 02468acf 01234567 0091a2b3 0048d159 002468ac +00123456 00091a2b 00048d15 0002468a 00012345 000091a2 000048d1 00002468 +00001234 0000091a 0000048d 00000246 00000123 00000091 00000048 00000024 +00000012 00000009 00000004 00000002 00000001 00000000 00000000 00000000 + +92345678 c91a2b3c e48d159e f2468acf f9234567 fc91a2b3 fe48d159 ff2468ac +ff923456 ffc91a2b ffe48d15 fff2468a fff92345 fffc91a2 fffe48d1 ffff2468 +ffff9234 ffffc91a ffffe48d fffff246 fffff923 fffffc91 fffffe48 ffffff24 +ffffff92 ffffffc9 ffffffe4 fffffff2 fffffff9 fffffffc fffffffe ffffffff + +12345678 2468acf0 48d159e0 91a2b3c0 23456780 468acf00 8d159e00 1a2b3c00 +34567800 68acf000 d159e000 a2b3c000 45678000 8acf0000 159e0000 2b3c0000 +56780000 acf00000 59e00000 b3c00000 67800000 cf000000 9e000000 3c000000 +78000000 f0000000 e0000000 c0000000 80000000 00000000 00000000 00000000 + + +0 7 14 21 28 35 42 49 56 63 70 +038f5ae5 038f5e06 038f6127 038f6448 038f6769 038f6a8a +05fb4e83 060091a4 0605d4c5 060b17e6 06105b07 06159e28 +00012345 000091a2 00006117 000048d1 00003a41 0000308b 0000299c 00002468 +0000205d +00000000 00000001 00000000 00000001 00000000 00000003 00000001 00000005 +00000000 + +00001234 00001235 00001236 00001237 00001238 00001239 0000123a 0000123b +0000123c 0000123d +00001234 00001233 00001232 00001231 00001230 0000122f 0000122e 0000122d +0000122c 0000122b + +00000220 00005335 00005115 ffffedcb 00001246 00001222 + +0 0 0 +1 1 1 +2 2 2 +3 3 3 +4 4 4 +5 5 5 +6 6 6 +7 7 7 +8 8 8 +9 9 9 + +3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 diff --git a/tools/pi.c b/tools/pi.c new file mode 100644 index 0000000..b201622 --- /dev/null +++ b/tools/pi.c @@ -0,0 +1,35 @@ +/*Calculate the value of PI. Takes a long time!*/ +#ifndef WIN32 +int putchar(char ch) +{ + *(int*)0x20000000 = ch; + return 0; +} + +void OS_InterruptServiceRoutine(unsigned int status) +{ + (void)status; +} +#endif + +void print_num(unsigned long num) +{ + unsigned long digit,offset; + for(offset=1000;offset;offset/=10) { + digit=num/offset; + putchar(digit+'0'); + num-=digit*offset; + } +} + +long a=10000,b,c=56,d,e,f[57],g; +int main() +{ + long a5=a/5; + for(;b-c;) f[b++]=a5; + for(;d=0,g=c*2;c-=14,print_num(e+d/a),e=d%a)for(b=c;d+=f[b]*a, + f[b]=d%--g,d/=g--,--b;d*=b); + putchar('\n'); + return 0; +} + diff --git a/tools/plasma.h b/tools/plasma.h new file mode 100644 index 0000000..4dc73cb --- /dev/null +++ b/tools/plasma.h @@ -0,0 +1,52 @@ +/*-------------------------------------------------------------------- + * TITLE: Plasma Hardware Defines + * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) + * DATE CREATED: 12/17/05 + * FILENAME: plasma.h + * PROJECT: Plasma CPU core + * COPYRIGHT: Software placed into the public domain by the author. + * Software 'as is' without warranty. Author liable for nothing. + * DESCRIPTION: + * Plasma Hardware Defines + *--------------------------------------------------------------------*/ +#ifndef __PLASMA_H__ +#define __PLASMA_H__ + +/*********** Hardware addesses ***********/ +#define RAM_INTERNAL_BASE 0x00000000 //8KB +#define RAM_EXTERNAL_BASE 0x10000000 //1MB +#define RAM_EXTERNAL_SIZE 0x00100000 +#define MISC_BASE 0x20000000 +#define UART_WRITE 0x20000000 +#define UART_READ 0x20000000 +#define IRQ_MASK 0x20000010 +#define IRQ_STATUS 0x20000020 +#define GPIO0_OUT 0x20000030 +#define GPIO0_CLEAR 0x20000040 +#define GPIOA_IN 0x20000050 +#define COUNTER_REG 0x20000060 +#define ETHERNET_REG 0x20000070 +#define FLASH_BASE 0x30000000 + +/*********** GPIO out bits ***************/ +#define ETHERNET_MDIO 0x00200000 +#define ETHERNET_MDIO_WE 0x00400000 +#define ETHERENT_MDC 0x00800000 +#define ETHERNET_ENABLE 0x01000000 + +/*********** Interrupt bits **************/ +#define IRQ_UART_READ_AVAILABLE 0x01 +#define IRQ_UART_WRITE_AVAILABLE 0x02 +#define IRQ_COUNTER18_NOT 0x04 +#define IRQ_COUNTER18 0x08 +#define IRQ_ETHERNET_RECEIVE 0x10 +#define IRQ_ETHERNET_TRANSMIT 0x20 +#define IRQ_GPIO31_NOT 0x40 +#define IRQ_GPIO31 0x80 + +/*********** Ethernet buffers ************/ +#define ETHERNET_RECEIVE 0x13ff0000 +#define ETHERNET_TRANSMIT 0x13fe0000 + +#endif //__PLASMA_H__ + diff --git a/tools/ram_image.c b/tools/ram_image.c new file mode 100644 index 0000000..e831459 --- /dev/null +++ b/tools/ram_image.c @@ -0,0 +1,133 @@ +/* ram_image.c by Steve Rhoads 11/7/05 + * This program take the ram_xilinx.vhd file as input + * and the code.txt file as input. + * It then creates ram_image.vhd as output with the + * initialization vectors set to the contents of code.txt. + + UPDATED: 09/07/10 Olivier Rinaudo (orinaudo@gmail.com) + new behaviour: 8KB expandable to 64KB of internal RAM + to be used with new ram_image.vhd enabling expandable + internal ram. + */ +#include +#include +#include + +//1MB buffer +#define BUF_SIZE (1024*1024) +//we have (up to) 8 blocks composed by 4 RAMB16_S9 instance (one per byte) +//each RAMB have 64 hex rows -> max=8*4*64 +#define RAM_BLOCKS (8) +#define RAM_SPLIT (4) +#define RAM_ROWS (64) +#define RAM_ROWS_TOTAL (RAM_BLOCKS*RAM_SPLIT*RAM_ROWS) +#define RAM_DWORDPERROW (8) + + +int main(int argc, char *argv[]) +{ + FILE *file; + int i, iposinrow, iblock, irowinsplit, index, size, count; + char *buf, *ptr, *ptr_list[RAM_ROWS_TOTAL], text[80]; + unsigned int *code; + + if(argc < 4) + { + printf("Usage: ram_image \n"); + printf("Usage: ram_image ram_xilinx.vhd code.txt ram_image.vhd\n"); + return 0; + } + + buf = (char*)malloc(BUF_SIZE); + code = (unsigned int*)malloc(BUF_SIZE); + + //Read ram_xilinx.vhd + file = fopen(argv[1], "rb"); + if(file == NULL) + { + printf("Can't open '%s'!\n", argv[1]); + return -1; + } + size = fread(buf, 1, BUF_SIZE, file); + fclose(file); + + //Read code.txt + file = fopen(argv[2], "r"); + if(file == NULL) + { + printf("Can't open '%s'!\n", argv[2]); + return -1; + } + //store DWORDs in code buffer + for(count = 0; count < RAM_ROWS_TOTAL*RAM_DWORDPERROW; ++count) + { + if(feof(file)) + { + count--; + break; + } + fscanf(file, "%x", &code[count]); + } + fclose(file); + + //Find 'INIT_00 => X"' + + //start at buf, then seek next occurence + ptr = buf; + for(i = 0; i < RAM_ROWS_TOTAL; ++i) + { + sprintf(text, "INIT_%2.2X => X\"", i % RAM_ROWS); + ptr = strstr(ptr, text); + if(ptr == NULL) + { + printf("ERROR: Can't find '%s', block %d, instance %d in '%s'!\n", + text, (i/(RAM_SPLIT*RAM_ROWS)), + (i%(RAM_SPLIT*RAM_ROWS))/RAM_ROWS, argv[1]); + return -1; + } + ptr_list[i] = ptr + strlen(text); + } + + //Modify vhdl source code + iposinrow = RAM_DWORDPERROW*8-2; //start filling from end of line + iblock = 0; + irowinsplit = 0; + for(i = 0; i < count; ++i) + { + sprintf(text, "%8.8x", code[i]); + index = iblock*RAM_ROWS*RAM_SPLIT+irowinsplit; + + ptr_list[index][iposinrow] = text[0]; + ptr_list[index][iposinrow+1] = text[1]; + ptr_list[index+RAM_ROWS][iposinrow] = text[2]; + ptr_list[index+RAM_ROWS][iposinrow+1] = text[3]; + ptr_list[index+RAM_ROWS*2][iposinrow] = text[4]; + ptr_list[index+RAM_ROWS*2][iposinrow+1] = text[5]; + ptr_list[index+RAM_ROWS*3][iposinrow] = text[6]; + ptr_list[index+RAM_ROWS*3][iposinrow+1] = text[7]; + iposinrow -= 2; + if(iposinrow < 0) + { + iposinrow = RAM_DWORDPERROW*8-2; //reset row + irowinsplit++; + if (irowinsplit>RAM_ROWS-1) + { + irowinsplit = 0; + iblock++; + } + } + } + + //Write ram_image.vhd + file = fopen(argv[3], "wb"); + if(file == NULL) + { + printf("Can't write '%s'!\n", argv[3]); + return -1; + } + fwrite(buf, 1, size, file); + fclose(file); + free(buf); + free(code); + return 0; +} diff --git a/tools/test.c b/tools/test.c new file mode 100644 index 0000000..d1fa625 --- /dev/null +++ b/tools/test.c @@ -0,0 +1,237 @@ +/*------------------------------------------------------------------- +-- TITLE: Plasma CPU test code +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 4/21/01 +-- FILENAME: test.c +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- The executable image of this file is used as input to the VHDL. +-- +-- This file must not contain any global or static data since +-- there isn't a loader to relocate the .data segment and since +-- having static data causes the opcodes to begin at a different +-- location in the resulting executable file. +-- +-- Save the opcodes in "code.txt". +-- +-- Testing subversion. +--------------------------------------------------------------------*/ +#ifndef WIN32 +#undef putchar +#define putchar(C) *(volatile unsigned char*)0x20000000=(unsigned char)(C) +#endif + +void print_hex(unsigned long num); + +char text[]="Testing the Plasma core.\n"; +char buf[20]; +int xyz=0xbadbeef; +int abc; + +char *strcpy2(char *s, const char *t) +{ + char *tmp=s; + while((int)(*s++=*t++)) ; + return(tmp); +} + +static void itoa2(long n, char *s, int base, long *digits) +{ + long i,j,sign; + unsigned long n2; + char number[20]; + for(i=0;i<15;++i) { + number[i]=' '; + } + number[15]=0; + if(n>=0||base!=10) { + sign=1; + } else { + sign=-1; + } + n2=n*sign; + for(j=14;j>=0;--j) { + i=n2%base; + n2/=base; + number[j]=i<10?'0'+i:'a'+i-10; + if(n2==0&&15-j>=*digits) break; + } + if(sign==-1) { + number[--j]='-'; + } + if(*digits==0||*digits<15-j) { + strcpy2(s,&number[j]); + *digits=15-j; + } else { + strcpy2(s,&number[15-*digits]); + } +} + +void print(long num,long base,long digits) +{ + char *ptr,buffer[128]; + itoa2(num,buffer,base,&digits); + ptr=buffer; + while(*ptr) { + putchar(*ptr++); /* Put the character out */ + if(ptr[-1]=='\n') *--ptr='\r'; + } +} + +void print_string(char *p) +{ + int i; + for(i=0;p[i];++i) { + putchar(p[i]); + } +} + +int prime() +{ + int i,j; + //show all prime numbers less than 1000 + for(i=3;i<1000;i+=2) { + for(j=3;j>i); + putchar(' '); + } + putchar('\n'); + j=0x92345678; + for(i=0;i<32;++i) { + print_hex(j>>i); + putchar(' '); + } + putchar('\n'); + j=0x12345678; + for(i=0;i<32;++i) { + print_hex(j< +#include +#include +#include + +#define BUF_SIZE (1024*1024*4) +#define LINE_SIZE 10000 + +char drop_char[10000]; + +int main(int argc, char *argv[]) +{ + FILE *file; + char *buf,*ptr_in,*ptr_out,*line_store,*line; + char *line_start,*source_start; + int bytes,digits,value,isbinary,col,col_num,row,drop_cnt; + int col_index,line_index,back_count,drop_start=0; + int digits_length=0; + (void)argc; + (void)argv; + + printf("tracehex\n"); + + /* Reading trace.txt */ + file=fopen("trace.txt","r"); + if(file==NULL) { + printf("Can't open file\n"); + return -1; + } + line_store=(char*)malloc(LINE_SIZE); + line_store[0]=' '; + line=line_store+1; + buf=(char*)malloc(BUF_SIZE*2); + if(buf==NULL) { + printf("Can't malloc!\n"); + return -1; + } + ptr_out=buf+BUF_SIZE; + bytes=fread(buf,1,BUF_SIZE-1,file); + buf[bytes]=0; + fclose(file); + + digits=0; + value=0; + isbinary=0; + col=0; + col_num=0; + row=0; + line_start=ptr_out; + source_start=buf; + for(ptr_in=strstr(buf,"=");*ptr_in;++ptr_in) { + ++col; + if(drop_start==0&&*ptr_in==' ') { + for(drop_start=3;drop_start<30;++drop_start) { + if(ptr_in[drop_start]!=' ') { + break; + } + } + for(;drop_start<30;++drop_start) { + if(ptr_in[drop_start]==' ') { + break; + } + } + drop_start-=2; + } + if(col<4) { + drop_char[col]=1; + continue; + } + if(drop_start<=col&&col<=drop_start+2) { + drop_char[col]=1; + continue; + } + if(col10) { + isbinary=1; + col_num=col; + for(digits_length=1;!isspace(ptr_in[digits_length]);++digits_length) ; + --digits_length; + } + } else { + isbinary=0; + } + *ptr_out++=*ptr_in; + digits=0; + value=0; + } + /* convert every four binary digits to a hex digit */ + if(digits&&(digits_length%4)==0) { + drop_char[--col_num]=0; + if(value<100) { + *ptr_out++=value<10?value+'0':value-10+'A'; + } else if(value<5000) { + *ptr_out++='Z'; + } else { + *ptr_out++='U'; + } + digits=0; + value=0; + } + --digits_length; + } + *ptr_out=0; + + /* now process the header */ + file=fopen("trace2.txt","w"); + col=0; + line[0]=0; + for(ptr_in=buf;*ptr_in;++ptr_in) { + if(*ptr_in=='=') { + break; + } + line[col++]=*ptr_in; + if(*ptr_in=='\n') { + line[col]=0; + line_index=0; + for(col_index=0;col_index 'Z'); + c_alu <= ZERO(31 downto 1) & less_than when alu_function=ALU_LESS_THAN or + alu_function=ALU_LESS_THAN_SIGNED else + (others => 'Z'); + c_alu <= a_in or b_in when alu_function=ALU_OR else (others => 'Z'); + c_alu <= a_in and b_in when alu_function=ALU_AND else (others => 'Z'); + c_alu <= a_in xor b_in when alu_function=ALU_XOR else (others => 'Z'); + c_alu <= a_in nor b_in when alu_function=ALU_NOR else (others => 'Z'); + c_alu <= ZERO when alu_function=ALU_NOTHING else (others => 'Z'); + end generate; + +end; --architecture logic + diff --git a/vhdl/build_dir/ISE_scripts/.svn/all-wcprops b/vhdl/build_dir/ISE_scripts/.svn/all-wcprops new file mode 100644 index 0000000..842ad96 --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 66 +/ocsvn/plasma/!svn/ver/371/plasma/trunk/vhdl/build_dir/ISE_scripts +END +makeprom.cmds +K 25 +svn:wc:ra_dav:version-url +V 80 +/ocsvn/plasma/!svn/ver/371/plasma/trunk/vhdl/build_dir/ISE_scripts/makeprom.cmds +END +loadprom.cmds +K 25 +svn:wc:ra_dav:version-url +V 80 +/ocsvn/plasma/!svn/ver/371/plasma/trunk/vhdl/build_dir/ISE_scripts/loadprom.cmds +END +main.scrs +K 25 +svn:wc:ra_dav:version-url +V 76 +/ocsvn/plasma/!svn/ver/371/plasma/trunk/vhdl/build_dir/ISE_scripts/main.scrs +END diff --git a/vhdl/build_dir/ISE_scripts/.svn/entries b/vhdl/build_dir/ISE_scripts/.svn/entries new file mode 100644 index 0000000..4afaab3 --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +397 +http://opencores.org/ocsvn/plasma/plasma/trunk/vhdl/build_dir/ISE_scripts +http://opencores.org/ocsvn/plasma + + + +2009-09-19T14:27:52.013014Z +371 +rhoads + + + + + + + + + + + + + + +8fa3edc1-71da-4d9b-a61a-8b20347ad903 + +makeprom.cmds +file + + + + +2011-02-13T19:50:04.000000Z +742e945d0e311b859783e976a933792f +2009-09-19T14:27:52.013014Z +371 +rhoads + + + + + + + + + + + + + + + + + + + + + +227 + +loadprom.cmds +file + + + + +2011-02-13T19:50:04.000000Z +eb02daa158e0488719dacaa14047ce1d +2009-09-19T14:27:52.013014Z +371 +rhoads + + + + + + + + + + + + + + + + + + + + + +106 + +main.scrs +file + + + + +2011-02-13T19:50:04.000000Z +2a2930a7a56192b5a15054584820bf1b +2009-09-19T14:27:52.013014Z +371 +rhoads + + + + + + + + + + + + + + + + + + + + + +101 + diff --git a/vhdl/build_dir/ISE_scripts/.svn/text-base/loadprom.cmds.svn-base b/vhdl/build_dir/ISE_scripts/.svn/text-base/loadprom.cmds.svn-base new file mode 100644 index 0000000..0803e2e --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/.svn/text-base/loadprom.cmds.svn-base @@ -0,0 +1,6 @@ +setMode -bscan +setCable -p auto +identify +assignFile -p 2 -file generated/main.mcs +program -e -p 2 -v +quit diff --git a/vhdl/build_dir/ISE_scripts/.svn/text-base/main.scrs.svn-base b/vhdl/build_dir/ISE_scripts/.svn/text-base/main.scrs.svn-base new file mode 100644 index 0000000..c58f9b9 --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/.svn/text-base/main.scrs.svn-base @@ -0,0 +1,7 @@ +run +-ifn main.prj +-ifmt VHDL +-ofn main.ngc +-ofmt NGC -p XC3S500E-FG320-4 +-opt_mode Area +-opt_level 2 diff --git a/vhdl/build_dir/ISE_scripts/.svn/text-base/makeprom.cmds.svn-base b/vhdl/build_dir/ISE_scripts/.svn/text-base/makeprom.cmds.svn-base new file mode 100644 index 0000000..e484f0a --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/.svn/text-base/makeprom.cmds.svn-base @@ -0,0 +1,8 @@ +setMode -pff +setSubmode -pffserial +addPromDevice -p 1 -name xcf04s +addDesign -version 0 -name 0 +addDeviceChain -index 0 +addDevice -p 1 -file generated/main.bit +generate -format mcs -fillvalue FF -output generated/main.mcs +quit diff --git a/vhdl/build_dir/ISE_scripts/loadprom.cmds b/vhdl/build_dir/ISE_scripts/loadprom.cmds new file mode 100644 index 0000000..0803e2e --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/loadprom.cmds @@ -0,0 +1,6 @@ +setMode -bscan +setCable -p auto +identify +assignFile -p 2 -file generated/main.mcs +program -e -p 2 -v +quit diff --git a/vhdl/build_dir/ISE_scripts/main.scrs b/vhdl/build_dir/ISE_scripts/main.scrs new file mode 100644 index 0000000..c58f9b9 --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/main.scrs @@ -0,0 +1,7 @@ +run +-ifn main.prj +-ifmt VHDL +-ofn main.ngc +-ofmt NGC -p XC3S500E-FG320-4 +-opt_mode Area +-opt_level 2 diff --git a/vhdl/build_dir/ISE_scripts/makeprom.cmds b/vhdl/build_dir/ISE_scripts/makeprom.cmds new file mode 100644 index 0000000..e484f0a --- /dev/null +++ b/vhdl/build_dir/ISE_scripts/makeprom.cmds @@ -0,0 +1,8 @@ +setMode -pff +setSubmode -pffserial +addPromDevice -p 1 -name xcf04s +addDesign -version 0 -name 0 +addDeviceChain -index 0 +addDevice -p 1 -file generated/main.bit +generate -format mcs -fillvalue FF -output generated/main.mcs +quit diff --git a/vhdl/build_dir/Makefile b/vhdl/build_dir/Makefile new file mode 100644 index 0000000..5ffd488 --- /dev/null +++ b/vhdl/build_dir/Makefile @@ -0,0 +1,144 @@ +# Makefile for Plasma on the s3Esk +# For Linux development environment using free GHDL simulator and +# Xilinx synthesis tools. +# Derives from the DDRSDRAM-on-s3Esk makefile +# +# This makefile was created by me, Dan Clemmensen. I hereby place it in +# the public domain, releasing any rights. I retain the right to re-use +# this work as the basis for a derived work. +# +# Use GHDL for simulation, and then use the Xilinx tools in batch mode for +# synthesis and download. +# Before you use this makefile for the first time, you will need to build +# the plasma tools. After that, you can do the rest of the development +# using this makefile, unless you change a tool. +# Place this makefile and the associated ISE_scripts directory in a +# subdirectory of the VHDL directory. We use this approach because the Xilinx +# tools create a large number of temporary files in the working directory. +# +# Usage: +# make clean # removes derived files and directories +# make load # builds everthing from scratch and +# # loads the flash mem on the target +# make simtest # builds and runs as a GHDL simulation +# make view # displays the results of the simulation + +# To help isolate problems, you may run a series of steps instead of the whole +# "make load." Look below to see them. + +# VHDL_DIR is the top-level VHDL directory for Plasma. +VHDL_DIR = .. +# PROJ_VHDL comprises files used in both the actual target and the sim +PROJ_VHDL = \ + $(VHDL_DIR)/mlite_pack.vhd \ + $(VHDL_DIR)/plasma_3e.vhd \ + $(VHDL_DIR)/ddr_ctrl.vhd \ + $(VHDL_DIR)/plasma.vhd \ + generated/ram_image.vhd \ + $(VHDL_DIR)/uart.vhd \ + $(VHDL_DIR)/eth_dma.vhd \ + $(VHDL_DIR)/mlite_cpu.vhd \ + $(VHDL_DIR)/alu.vhd \ + $(VHDL_DIR)/bus_mux.vhd \ + $(VHDL_DIR)/control.vhd \ + $(VHDL_DIR)/mem_ctrl.vhd \ + $(VHDL_DIR)/mult.vhd \ + $(VHDL_DIR)/pipeline.vhd \ + $(VHDL_DIR)/pc_next.vhd \ + $(VHDL_DIR)/reg_bank.vhd \ + $(VHDL_DIR)/shifter.vhd \ + $(VHDL_DIR)/cache.vhd + +# TARGET_VHDL comprises files used on the target but not in sim +TARGET_VHDL = + +# SIM_VHDL comprises files used in sim but not on the target +# for this sim, these simulate the rest of the S3Esk board +SIM_DIR = $(VHDL_DIR)/simulation +SIM_VHDL = \ + $(VHDL_DIR)/mt46v16m16.vhd \ + $(VHDL_DIR)/tbench.vhd + +SIM_TOP = tbench +GCC_PARAMS= + +OBJS = $(VHDL:.vhd=.o) + +# GHDL config +OBJDIR = obj +ISE_DIR=/opt/Xilinx/11.1/ISE +GHDL_LIBS = $(ISE_DIR)/ghdl/unisim +GHDL_FLAGS = --ieee=synopsys -fexplicit -P$(GHDL_LIBS) +GHDL_FLAGS += --workdir=$(OBJDIR) --warn-no-vital-generic + +%.o: %.vhd + ghdl -a $(GHDL_FLAGS) $< + +all: simtest + +old: workdir $(OBJS) + +# invocation strings for helper tools to build Xilinx BRAM memory images. +TOOLS = ../../tools +# generate the ram_image.vhd +generated: + rm -rf generated + mkdir generated + $(TOOLS)/ram_image.exe $(VHDL_DIR)/ram_xilinx.vhd $(TOOLS)/code.txt generated/ram_image.vhd + +NAME=main +workdir: + mkdir -p $(OBJDIR) + +clean: + rm -rf *.o *.cf $(OBJDIR) tb *.vcd main $(SIM_TOP) *.ghw + rm -f *.bit *.bgn *_pad.txt *_pad.csv *.xpi *.srp *.ngc *.par + rm -f *.lst *.ngd *.ngm *.pcf *.mrp *.unroutes *.pad + rm -f *.bld *.ncd *.twr *.drc + rm -rf xst $(NAME).prj + rm -rf generated + +simtest: workdir generated + ghdl -i $(GHDL_FLAGS) $(PROJ_VHDL) $(SIM_VHDL) + ghdl -m $(GHDL_FLAGS) $(SIM_TOP) +sim: + ghdl -r $(SIM_TOP) --stop-time=10ms --wave=generated/out.ghw 2> /dev/null + +view: + gtkwave generated/out.ghw view.sav + +#Xilinx ISE actions. Uses a wrapper script named "xilinx" to run the ISE batch commands + +# create an ISE project file from the list of VHDL files +$(NAME).prj: $(PROJ_VHDL) $(TARGET_VHDL) + echo $(PROJ_VHDL) $(TARGET_VHDL)|tr " " "\n">$(NAME).prj + +bitfile: generated step0 step1 step2 step3 step4 step5 + +step0: $(NAME).prj + xilinx xst -ifn ISE_scripts/$(NAME).scrs -ofn $(NAME).srp +step1: + xilinx ngdbuild -nt on -uc ../spartan3e.ucf $(NAME).ngc $(NAME).ngd +step2: + xilinx map -pr b $(NAME).ngd -o $(NAME).ncd $(NAME).pcf +step3: + xilinx par -w -ol high $(NAME).ncd $(NAME).ncd $(NAME).pcf +step4: + xilinx trce -v 10 -o $(NAME).twr $(NAME).ncd $(NAME).pcf +step5: + xilinx bitgen $(NAME).ncd generated/$(NAME).bit -w #-f $(NAME).ut + +generated/main.bit: bitfile + +mcs: generated/main.bit + xilinx impact -batch ISE_scripts/makeprom.cmds + +generated/main.mcs: mcs + +load: generated/main.mcs + xilinx impact -batch ISE_scripts/loadprom.cmds + +impact: + xilinx impact +ise: $(NAME).prj + xilinx ise diff --git a/vhdl/bus_mux.vhd b/vhdl/bus_mux.vhd new file mode 100644 index 0000000..0d94858 --- /dev/null +++ b/vhdl/bus_mux.vhd @@ -0,0 +1,136 @@ +--------------------------------------------------------------------- +-- TITLE: Bus Multiplexer / Signal Router +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/8/01 +-- FILENAME: bus_mux.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- This entity is the main signal router. +-- It multiplexes signals from multiple sources to the correct location. +-- The outputs are as follows: +-- a_bus : goes to the ALU +-- b_bus : goes to the ALU +-- reg_dest_out : goes to the register bank +-- take_branch : goes to pc_next +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; + +entity bus_mux is + port(imm_in : in std_logic_vector(15 downto 0); + reg_source : in std_logic_vector(31 downto 0); + a_mux : in a_source_type; + a_out : out std_logic_vector(31 downto 0); + + reg_target : in std_logic_vector(31 downto 0); + b_mux : in b_source_type; + b_out : out std_logic_vector(31 downto 0); + + c_bus : in std_logic_vector(31 downto 0); + c_memory : in std_logic_vector(31 downto 0); + c_pc : in std_logic_vector(31 downto 2); + c_pc_plus4 : in std_logic_vector(31 downto 2); + c_mux : in c_source_type; + reg_dest_out : out std_logic_vector(31 downto 0); + + branch_func : in branch_function_type; + take_branch : out std_logic); +end; --entity bus_mux + +architecture logic of bus_mux is +begin + +--Determine value of a_bus +amux: process(reg_source, imm_in, a_mux, c_pc) +begin + case a_mux is + when A_FROM_REG_SOURCE => + a_out <= reg_source; + when A_FROM_IMM10_6 => + a_out <= ZERO(31 downto 5) & imm_in(10 downto 6); + when A_FROM_PC => + a_out <= c_pc & "00"; + when others => + a_out <= c_pc & "00"; + end case; +end process; + +--Determine value of b_bus +bmux: process(reg_target, imm_in, b_mux) +begin + case b_mux is + when B_FROM_REG_TARGET => + b_out <= reg_target; + when B_FROM_IMM => + b_out <= ZERO(31 downto 16) & imm_in; + when B_FROM_SIGNED_IMM => + if imm_in(15) = '0' then + b_out(31 downto 16) <= ZERO(31 downto 16); + else + b_out(31 downto 16) <= "1111111111111111"; + end if; + b_out(15 downto 0) <= imm_in; + when B_FROM_IMMX4 => + if imm_in(15) = '0' then + b_out(31 downto 18) <= "00000000000000"; + else + b_out(31 downto 18) <= "11111111111111"; + end if; + b_out(17 downto 0) <= imm_in & "00"; + when others => + b_out <= reg_target; + end case; +end process; + +--Determine value of c_bus +cmux: process(c_bus, c_memory, c_pc, c_pc_plus4, imm_in, c_mux) +begin + case c_mux is + when C_FROM_ALU => -- | C_FROM_SHIFT | C_FROM_MULT => + reg_dest_out <= c_bus; + when C_FROM_MEMORY => + reg_dest_out <= c_memory; + when C_FROM_PC => + reg_dest_out <= c_pc(31 downto 2) & "00"; + when C_FROM_PC_PLUS4 => + reg_dest_out <= c_pc_plus4 & "00"; + when C_FROM_IMM_SHIFT16 => + reg_dest_out <= imm_in & ZERO(15 downto 0); + when others => + reg_dest_out <= c_bus; + end case; +end process; + +--Determine value of take_branch +pc_mux: process(branch_func, reg_source, reg_target) + variable is_equal : std_logic; +begin + if reg_source = reg_target then + is_equal := '1'; + else + is_equal := '0'; + end if; + case branch_func is + when BRANCH_LTZ => + take_branch <= reg_source(31); + when BRANCH_LEZ => + take_branch <= reg_source(31) or is_equal; + when BRANCH_EQ => + take_branch <= is_equal; + when BRANCH_NE => + take_branch <= not is_equal; + when BRANCH_GEZ => + take_branch <= not reg_source(31); + when BRANCH_GTZ => + take_branch <= not reg_source(31) and not is_equal; + when BRANCH_YES => + take_branch <= '1'; + when others => + take_branch <= '0'; + end case; +end process; + +end; --architecture logic diff --git a/vhdl/cache.vhd b/vhdl/cache.vhd new file mode 100644 index 0000000..e3afc84 --- /dev/null +++ b/vhdl/cache.vhd @@ -0,0 +1,177 @@ +--------------------------------------------------------------------- +-- TITLE: Cache Controller +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 12/22/08 +-- FILENAME: cache.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Control 4KB unified cache that uses the upper 4KB of the 8KB +-- internal RAM. Only lowest 2MB of DDR is cached. +-- Only include file for Xilinx FPGAs. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +library UNISIM; +use UNISIM.vcomponents.all; +use work.mlite_pack.all; + +entity cache is + generic(memory_type : string := "DEFAULT"); + port(clk : in std_logic; + reset : in std_logic; + address_next : in std_logic_vector(31 downto 2); + byte_we_next : in std_logic_vector(3 downto 0); + cpu_address : in std_logic_vector(31 downto 2); + mem_busy : in std_logic; + + cache_access : out std_logic; --access 4KB cache + cache_checking : out std_logic; --checking if cache hit + cache_miss : out std_logic); --cache miss +end; --cache + +architecture logic of cache is + subtype state_type is std_logic_vector(1 downto 0); + constant STATE_IDLE : state_type := "00"; + constant STATE_CHECKING : state_type := "01"; + constant STATE_MISSED : state_type := "10"; + constant STATE_WAITING : state_type := "11"; + + signal state_reg : state_type; + signal state : state_type; + signal state_next : state_type; + + signal cache_address : std_logic_vector(10 downto 0); + signal cache_tag_in : std_logic_vector(8 downto 0); + signal cache_tag_reg : std_logic_vector(8 downto 0); + signal cache_tag_out : std_logic_vector(8 downto 0); + signal cache_we : std_logic; +begin + + cache_proc: process(clk, reset, mem_busy, cache_address, + state_reg, state, state_next, + address_next, byte_we_next, cache_tag_in, --Stage1 + cache_tag_reg, cache_tag_out, --Stage2 + cpu_address) --Stage3 + begin + + case state_reg is + when STATE_IDLE => --cache idle + cache_checking <= '0'; + cache_miss <= '0'; + state <= STATE_IDLE; + when STATE_CHECKING => --current read in cached range, check if match + cache_checking <= '1'; + if cache_tag_out /= cache_tag_reg or cache_tag_out = ONES(8 downto 0) then + cache_miss <= '1'; + state <= STATE_MISSED; + else + cache_miss <= '0'; + state <= STATE_IDLE; + end if; + when STATE_MISSED => --current read cache miss + cache_checking <= '0'; + cache_miss <= '1'; + if mem_busy = '1' then + state <= STATE_MISSED; + else + state <= STATE_WAITING; + end if; + when STATE_WAITING => --waiting for memory access to complete + cache_checking <= '0'; + cache_miss <= '0'; + if mem_busy = '1' then + state <= STATE_WAITING; + else + state <= STATE_IDLE; + end if; + when others => + cache_checking <= '0'; + cache_miss <= '0'; + state <= STATE_IDLE; + end case; --state + + if state = STATE_IDLE then --check if next access in cached range + cache_address <= '0' & address_next(11 downto 2); + if address_next(30 downto 21) = "0010000000" then --first 2MB of DDR + cache_access <= '1'; + if byte_we_next = "0000" then --read cycle + cache_we <= '0'; + state_next <= STATE_CHECKING; --need to check if match + else + cache_we <= '1'; --update cache tag + state_next <= STATE_WAITING; + end if; + else + cache_access <= '0'; + cache_we <= '0'; + state_next <= STATE_IDLE; + end if; + else + cache_address <= '0' & cpu_address(11 downto 2); + cache_access <= '0'; + if state = STATE_MISSED then + cache_we <= '1'; --update cache tag + else + cache_we <= '0'; + end if; + state_next <= state; + end if; + + if byte_we_next = "0000" or byte_we_next = "1111" then --read or 32-bit write + cache_tag_in <= address_next(20 downto 12); + else + cache_tag_in <= ONES(8 downto 0); --invalid tag + end if; + + if reset = '1' then + state_reg <= STATE_IDLE; + cache_tag_reg <= ZERO(8 downto 0); + elsif rising_edge(clk) then + state_reg <= state_next; + if state = STATE_IDLE and state_reg /= STATE_MISSED then + cache_tag_reg <= cache_tag_in; + end if; + end if; + + end process; + + cache_xilinx: if memory_type = "XILINX_16X" generate + begin + cache_tag: RAMB16_S9 --Xilinx specific + port map ( + DO => cache_tag_out(7 downto 0), + DOP => cache_tag_out(8 downto 8), + ADDR => cache_address, --registered + CLK => clk, + DI => cache_tag_in(7 downto 0), --registered + DIP => cache_tag_in(8 downto 8), + EN => '1', + SSR => ZERO(0), + WE => cache_we); + end generate; --cache_xilinx + + cache_generic: if memory_type /= "XILINX_16X" generate + begin + cache_tag: process(clk, cache_address, cache_tag_in, cache_we) + constant ADDRESS_WIDTH : natural := 10; + type storage_array is + array(natural range 0 to 2 ** ADDRESS_WIDTH - 1) of + std_logic_vector(8 downto 0); + variable storage : storage_array; + variable index : natural := 0; + begin + if rising_edge(clk) then + index := conv_integer(cache_address(ADDRESS_WIDTH-1 downto 0)); + if cache_we = '1' then + storage(index) := cache_tag_in; + end if; + cache_tag_out <= storage(index); + end if; + end process; --cache_tag + end generate; --cache_generic + +end; --logic + diff --git a/vhdl/code.txt b/vhdl/code.txt new file mode 100644 index 0000000..934d128 --- /dev/null +++ b/vhdl/code.txt @@ -0,0 +1,658 @@ +3c1c0000 +379c8a34 +3c040000 +34840a48 +3c050000 +34a50a64 +3c1d0000 +37bd0c60 +ac800000 +0085182a +1460fffd +24840004 +0c0001d5 +00000000 +0800000e +23bdff98 +afa10010 +afa20014 +afa30018 +afa4001c +afa50020 +afa60024 +afa70028 +afa8002c +afa90030 +afaa0034 +afab0038 +afac003c +afad0040 +afae0044 +afaf0048 +afb8004c +afb90050 +afbf0054 +401a7000 +235afffc +afba0058 +0000d810 +afbb005c +0000d812 +afbb0060 +23a50000 +3c062000 +8cc40020 +8cc60010 +0c00020a +00862024 +8fa10010 +8fa20014 +8fa30018 +8fa4001c +8fa50020 +8fa60024 +8fa70028 +8fa8002c +8fa90030 +8faa0034 +8fab0038 +8fac003c +8fad0040 +8fae0044 +8faf0048 +8fb8004c +8fb90050 +8fbf0054 +8fba0058 +8fbb005c +03600011 +8fbb0060 +03600013 +23bd0068 +341b0001 +03400008 +409b6000 +40026000 +03e00008 +40846000 +3c050000 +24a50160 +8ca60000 +ac06003c +8ca60004 +ac060040 +8ca60008 +ac060044 +8ca6000c +03e00008 +ac060048 +3c1a1000 +375a003c +03400008 +00000000 +ac900000 +ac910004 +ac920008 +ac93000c +ac940010 +ac950014 +ac960018 +ac97001c +ac9e0020 +ac9c0024 +ac9d0028 +ac9f002c +03e00008 +34020000 +8c900000 +8c910004 +8c920008 +8c93000c +8c940010 +8c950014 +8c960018 +8c97001c +8c9e0020 +8c9c0024 +8c9d0028 +8c9f002c +03e00008 +34a20000 +00850019 +00001012 +00002010 +03e00008 +acc40000 +3c020000 +24420a48 +a0400008 +24050007 +00403825 +3083000f +2862000a +10400003 +00a73021 +10000002 +24620030 +24620037 +a0c20000 +24a5ffff +04a1fff6 +00042102 +3c020000 +03e00008 +24420a48 +3c020000 +24420a58 +a040000a +00803025 +24050009 +00404025 +3c07cccc +34e7cccd +00c70019 +00a82021 +24a5ffff +00004810 +000918c2 +00031080 +00431021 +00021040 +00c21023 +24420030 +a0820000 +04a1fff4 +00603025 +3c020000 +03e00008 +24420a58 +27bdffe0 +afbf0018 +afb10014 +afb00010 +0c000090 +00808825 +0c0001ef +00402025 +3c040000 +0c0001ef +24840980 +3c023b9a +3442c9ff +0051102b +1040001e +3c030004 +34634b83 +00111242 +00430019 +3c030000 +246309cc +00002810 +000581c2 +00101080 +00431021 +8c440000 +0c0001ef +00000000 +3c040000 +0c0001ef +24840984 +00101140 +00501023 +00021080 +00501023 +00021100 +00501021 +000210c0 +00501023 +00021940 +00621823 +00031880 +00701821 +00031a40 +02238823 +3c0205f5 +3442e0ff +0051102b +10400023 +3c0255e6 +34423b89 +02220019 +3c030000 +246309cc +00002810 +00058642 +00101080 +00431021 +8c440000 +0c0001ef +00000000 +3c040000 +0c0001ef +24840990 +00101040 +00501021 +00021180 +00501023 +00021080 +00501023 +00021100 +00501023 +00021140 +00501021 +00021200 +02228823 +3c02000f +3442423f +0051102b +14400005 +3c020131 +3c040000 +0c0001ef +2484099c +3c020131 +34422cff +0051102b +10400021 +3c026b5f +3442ca6b +02220019 +3c030000 +246309cc +00002810 +00058582 +26020014 +00021080 +00431021 +8c440000 +0c0001ef +00000000 +0c0001de +24040020 +00101940 +00701823 +00031180 +00431023 +000210c0 +00501021 +00021880 +00431021 +000211c0 +02228823 +3c02000f +3442423f +0051102b +14400009 +3c02431b +3c040000 +0c0001ef +2484099c +3c02000f +3442423f +0051102b +10400017 +3c02431b +3442de83 +02220019 +3c030000 +246309cc +00002810 +00058482 +00101080 +00431021 +8c440000 +0c0001ef +00000000 +3c040000 +0c0001ef +248409a8 +00101940 +00701823 +00031180 +00431023 +000210c0 +00501021 +00021180 +02228823 +3c020001 +3442869f +0051102b +10400020 +3c030a7c +34635ac5 +00111142 +00430019 +3c030000 +246309cc +00002810 +000581c2 +00101080 +00431021 +8c440000 +0c0001ef +00000000 +3c040000 +0c0001ef +24840990 +00101040 +00501021 +00021980 +00431021 +00021080 +00501021 +00021080 +00501021 +00021140 +02228823 +2e2203e8 +10400005 +2e224e20 +3c040000 +0c0001ef +248409b4 +2e224e20 +1440001f +2e2203e8 +3c02d1b7 +34421759 +02220019 +3c030000 +246309cc +00002810 +00058342 +26020014 +00021080 +00431021 +8c440000 +0c0001ef +00000000 +0c0001de +24040020 +00101080 +00501021 +000210c0 +00501023 +00021100 +00501021 +00021100 +02228823 +2e2203e8 +10400008 +3c021062 +3c040000 +0c0001ef +248409b4 +2e2203e8 +14400017 +2e220064 +3c021062 +34424dd3 +02220019 +3c030000 +246309cc +00002810 +00058182 +00101080 +00431021 +8c440000 +0c0001ef +00000000 +3c040000 +0c0001ef +248409c0 +00101140 +00501023 +00021080 +00501021 +000210c0 +02228823 +2e220064 +14400017 +2e220014 +3c0251eb +3442851f +02220019 +3c030000 +246309cc +00002810 +00058142 +00101080 +00431021 +8c440000 +0c0001ef +00000000 +3c040000 +0c0001ef +24840990 +00101040 +00501021 +000210c0 +00501021 +00021080 +02228823 +2e220014 +14400014 +3c030000 +3c02cccc +3442cccd +02220019 +246309cc +00002810 +000580c2 +26020014 +00021080 +00431021 +8c440000 +0c0001ef +00000000 +0c0001de +24040020 +00101080 +00501021 +00021040 +02228823 +3c030000 +246309cc +00111080 +00431021 +8c440000 +0c0001ef +00000000 +0c0001de +2404000d +0c0001de +2404000a +8fbf0018 +8fb10014 +8fb00010 +03e00008 +27bd0020 +27bdffe8 +afbf0014 +afb00010 +24100003 +0c0000a8 +02002025 +00101040 +1000fffc +02028021 +3c022000 +34420020 +8c420000 +00000000 +30420002 +14400008 +3c022000 +3c032000 +34630020 +8c620000 +00000000 +30420002 +1040fffc +3c022000 +ac440000 +03e00008 +00000000 +27bdffe0 +afb00010 +00808025 +afbf0018 +afb10014 +92020000 +00000000 +1040000d +2411000a +00000000 +14510003 +00000000 +0c0001de +2404000d +92040000 +0c0001de +26100001 +92020000 +00000000 +1440fff5 +00000000 +8fbf0018 +8fb10014 +8fb00010 +00001025 +03e00008 +27bd0020 +27bdffe8 +afbf0010 +0c0001de +24040049 +8fbf0010 +00000000 +03e00008 +27bd0018 +3c022000 +34420020 +8c420000 +03e00008 +30420001 +27bdffe8 +afbf0010 +0c000212 +00000000 +1040fffd +3c022000 +8c420000 +8fbf0010 +00000000 +03e00008 +27bd0018 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +6e696e65 +74790000 +65696768 +74790000 +73657665 +6e747900 +73697874 +79000000 +66696674 +79000000 +666f7274 +79000000 +74686972 +74790000 +7477656e +74790000 +6e696e65 +7465656e +00000000 +65696768 +7465656e +00000000 +73657665 +6e746565 +6e000000 +73697874 +65656e00 +66696674 +65656e00 +666f7572 +7465656e +00000000 +74686972 +7465656e +00000000 +7477656c +76650000 +656c6576 +656e0000 +74656e00 +6e696e65 +00000000 +65696768 +74000000 +73657665 +6e000000 +73697800 +66697665 +00000000 +666f7572 +00000000 +74687265 +65000000 +74776f00 +6f6e6500 +00000000 +3a200000 +2062696c +6c696f6e +20000000 +2068756e +64726564 +20000000 +6d696c6c +696f6e20 +00000000 +206d696c +6c696f6e +20000000 +74686f75 +73616e64 +20000000 +2074686f +7573616e +64200000 +0000097c +00000978 +00000974 +0000096c +00000964 +0000095c +00000958 +00000950 +00000948 +00000940 +0000093c +00000934 +0000092c +00000920 +00000914 +0000090c +00000904 +000008f8 +000008ec +000008e0 +0000097c +0000093c +000008d8 +000008d0 +000008c8 +000008c0 +000008b8 +000008b0 +000008a8 +000008a0 +00000000 diff --git a/vhdl/control.vhd b/vhdl/control.vhd new file mode 100644 index 0000000..aa240bf --- /dev/null +++ b/vhdl/control.vhd @@ -0,0 +1,482 @@ +--------------------------------------------------------------------- +-- TITLE: Controller / Opcode Decoder +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/8/01 +-- FILENAME: control.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- NOTE: MIPS(tm) is a registered trademark of MIPS Technologies. +-- MIPS Technologies does not endorse and is not associated with +-- this project. +-- DESCRIPTION: +-- Controls the CPU by decoding the opcode and generating control +-- signals to the rest of the CPU. +-- This entity decodes the MIPS(tm) opcode into a +-- Very-Long-Word-Instruction. +-- The 32-bit opcode is converted to a +-- 6+6+6+16+4+2+4+3+2+2+3+2+4 = 60 bit VLWI opcode. +-- Based on information found in: +-- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich +-- and "The Designer's Guide to VHDL" by Peter J. Ashenden +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; + +entity control is + port(opcode : in std_logic_vector(31 downto 0); + intr_signal : in std_logic; + rs_index : out std_logic_vector(5 downto 0); + rt_index : out std_logic_vector(5 downto 0); + rd_index : out std_logic_vector(5 downto 0); + imm_out : out std_logic_vector(15 downto 0); + alu_func : out alu_function_type; + shift_func : out shift_function_type; + mult_func : out mult_function_type; + branch_func : out branch_function_type; + a_source_out : out a_source_type; + b_source_out : out b_source_type; + c_source_out : out c_source_type; + pc_source_out: out pc_source_type; + mem_source_out:out mem_source_type; + exception_out: out std_logic); +end; --entity control + +architecture logic of control is +begin + +control_proc: process(opcode, intr_signal) + variable op, func : std_logic_vector(5 downto 0); + variable rs, rt, rd : std_logic_vector(5 downto 0); + variable rtx : std_logic_vector(4 downto 0); + variable imm : std_logic_vector(15 downto 0); + variable alu_function : alu_function_type; + variable shift_function : shift_function_type; + variable mult_function : mult_function_type; + variable a_source : a_source_type; + variable b_source : b_source_type; + variable c_source : c_source_type; + variable pc_source : pc_source_type; + variable branch_function: branch_function_type; + variable mem_source : mem_source_type; + variable is_syscall : std_logic; +begin + alu_function := ALU_NOTHING; + shift_function := SHIFT_NOTHING; + mult_function := MULT_NOTHING; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_REG_TARGET; + c_source := C_FROM_NULL; + pc_source := FROM_INC4; + branch_function := BRANCH_EQ; + mem_source := MEM_FETCH; + op := opcode(31 downto 26); + rs := '0' & opcode(25 downto 21); + rt := '0' & opcode(20 downto 16); + rtx := opcode(20 downto 16); + rd := '0' & opcode(15 downto 11); + func := opcode(5 downto 0); + imm := opcode(15 downto 0); + is_syscall := '0'; + + case op is + when "000000" => --SPECIAL + case func is + when "000000" => --SLL r[rd]=r[rt]< --SRL r[rd]=u[rt]>>re; + a_source := A_FROM_IMM10_6; + c_source := C_FROM_shift; + shift_function := SHIFT_RIGHT_UNSIGNED; + + when "000011" => --SRA r[rd]=r[rt]>>re; + a_source := A_FROM_IMM10_6; + c_source := C_FROM_SHIFT; + shift_function := SHIFT_RIGHT_SIGNED; + + when "000100" => --SLLV r[rd]=r[rt]< --SRLV r[rd]=u[rt]>>r[rs]; + c_source := C_FROM_SHIFT; + shift_function := SHIFT_RIGHT_UNSIGNED; + + when "000111" => --SRAV r[rd]=r[rt]>>r[rs]; + c_source := C_FROM_SHIFT; + shift_function := SHIFT_RIGHT_SIGNED; + + when "001000" => --JR s->pc_next=r[rs]; + pc_source := FROM_BRANCH; + alu_function := ALU_ADD; + branch_function := BRANCH_YES; + + when "001001" => --JALR r[rd]=s->pc_next; s->pc_next=r[rs]; + c_source := C_FROM_PC_PLUS4; + pc_source := FROM_BRANCH; + alu_function := ALU_ADD; + branch_function := BRANCH_YES; + + --when "001010" => --MOVZ if(!r[rt]) r[rd]=r[rs]; /*IV*/ + --when "001011" => --MOVN if(r[rt]) r[rd]=r[rs]; /*IV*/ + + when "001100" => --SYSCALL + is_syscall := '1'; + + when "001101" => --BREAK s->wakeup=1; + is_syscall := '1'; + + --when "001111" => --SYNC s->wakeup=1; + + when "010000" => --MFHI r[rd]=s->hi; + c_source := C_FROM_MULT; + mult_function := MULT_READ_HI; + + when "010001" => --MTHI s->hi=r[rs]; + mult_function := MULT_WRITE_HI; + + when "010010" => --MFLO r[rd]=s->lo; + c_source := C_FROM_MULT; + mult_function := MULT_READ_LO; + + when "010011" => --MTLO s->lo=r[rs]; + mult_function := MULT_WRITE_LO; + + when "011000" => --MULT s->lo=r[rs]*r[rt]; s->hi=0; + mult_function := MULT_SIGNED_MULT; + + when "011001" => --MULTU s->lo=r[rs]*r[rt]; s->hi=0; + mult_function := MULT_MULT; + + when "011010" => --DIV s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; + mult_function := MULT_SIGNED_DIVIDE; + + when "011011" => --DIVU s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; + mult_function := MULT_DIVIDE; + + when "100000" => --ADD r[rd]=r[rs]+r[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_ADD; + + when "100001" => --ADDU r[rd]=r[rs]+r[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_ADD; + + when "100010" => --SUB r[rd]=r[rs]-r[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_SUBTRACT; + + when "100011" => --SUBU r[rd]=r[rs]-r[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_SUBTRACT; + + when "100100" => --AND r[rd]=r[rs]&r[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_AND; + + when "100101" => --OR r[rd]=r[rs]|r[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_OR; + + when "100110" => --XOR r[rd]=r[rs]^r[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_XOR; + + when "100111" => --NOR r[rd]=~(r[rs]|r[rt]); + c_source := C_FROM_ALU; + alu_function := ALU_NOR; + + when "101010" => --SLT r[rd]=r[rs] --SLTU r[rd]=u[rs] --DADDU r[rd]=r[rs]+u[rt]; + c_source := C_FROM_ALU; + alu_function := ALU_ADD; + + --when "110001" => --TGEU + --when "110010" => --TLT + --when "110011" => --TLTU + --when "110100" => --TEQ + --when "110110" => --TNE + when others => + end case; + + when "000001" => --REGIMM + rt := "000000"; + rd := "011111"; + a_source := A_FROM_PC; + b_source := B_FROM_IMMX4; + alu_function := ALU_ADD; + pc_source := FROM_BRANCH; + branch_function := BRANCH_GTZ; + --if(test) pc=pc+imm*4 + + case rtx is + when "10000" => --BLTZAL r[31]=s->pc_next; branch=r[rs]<0; + c_source := C_FROM_PC_PLUS4; + branch_function := BRANCH_LTZ; + + when "00000" => --BLTZ branch=r[rs]<0; + branch_function := BRANCH_LTZ; + + when "10001" => --BGEZAL r[31]=s->pc_next; branch=r[rs]>=0; + c_source := C_FROM_PC_PLUS4; + branch_function := BRANCH_GEZ; + + when "00001" => --BGEZ branch=r[rs]>=0; + branch_function := BRANCH_GEZ; + + --when "10010" => --BLTZALL r[31]=s->pc_next; lbranch=r[rs]<0; + --when "00010" => --BLTZL lbranch=r[rs]<0; + --when "10011" => --BGEZALL r[31]=s->pc_next; lbranch=r[rs]>=0; + --when "00011" => --BGEZL lbranch=r[rs]>=0; + + when others => + end case; + + when "000011" => --JAL r[31]=s->pc_next; s->pc_next=(s->pc&0xf0000000)|target; + c_source := C_FROM_PC_PLUS4; + rd := "011111"; + pc_source := FROM_OPCODE25_0; + + when "000010" => --J s->pc_next=(s->pc&0xf0000000)|target; + pc_source := FROM_OPCODE25_0; + + when "000100" => --BEQ branch=r[rs]==r[rt]; + a_source := A_FROM_PC; + b_source := B_FROM_IMMX4; + alu_function := ALU_ADD; + pc_source := FROM_BRANCH; + branch_function := BRANCH_EQ; + + when "000101" => --BNE branch=r[rs]!=r[rt]; + a_source := A_FROM_PC; + b_source := B_FROM_IMMX4; + alu_function := ALU_ADD; + pc_source := FROM_BRANCH; + branch_function := BRANCH_NE; + + when "000110" => --BLEZ branch=r[rs]<=0; + a_source := A_FROM_PC; + b_source := b_FROM_IMMX4; + alu_function := ALU_ADD; + pc_source := FROM_BRANCH; + branch_function := BRANCH_LEZ; + + when "000111" => --BGTZ branch=r[rs]>0; + a_source := A_FROM_PC; + b_source := B_FROM_IMMX4; + alu_function := ALU_ADD; + pc_source := FROM_BRANCH; + branch_function := BRANCH_GTZ; + + when "001000" => --ADDI r[rt]=r[rs]+(short)imm; + b_source := B_FROM_SIGNED_IMM; + c_source := C_FROM_ALU; + rd := rt; + alu_function := ALU_ADD; + + when "001001" => --ADDIU u[rt]=u[rs]+(short)imm; + b_source := B_FROM_SIGNED_IMM; + c_source := C_FROM_ALU; + rd := rt; + alu_function := ALU_ADD; + + when "001010" => --SLTI r[rt]=r[rs]<(short)imm; + b_source := B_FROM_SIGNED_IMM; + c_source := C_FROM_ALU; + rd := rt; + alu_function := ALU_LESS_THAN_SIGNED; + + when "001011" => --SLTIU u[rt]=u[rs]<(unsigned long)(short)imm; + b_source := B_FROM_SIGNED_IMM; + c_source := C_FROM_ALU; + rd := rt; + alu_function := ALU_LESS_THAN; + + when "001100" => --ANDI r[rt]=r[rs]&imm; + b_source := B_FROM_IMM; + c_source := C_FROM_ALU; + rd := rt; + alu_function := ALU_AND; + + when "001101" => --ORI r[rt]=r[rs]|imm; + b_source := B_FROM_IMM; + c_source := C_FROM_ALU; + rd := rt; + alu_function := ALU_OR; + + when "001110" => --XORI r[rt]=r[rs]^imm; + b_source := B_FROM_IMM; + c_source := C_FROM_ALU; + rd := rt; + alu_function := ALU_XOR; + + when "001111" => --LUI r[rt]=(imm<<16); + c_source := C_FROM_IMM_SHIFT16; + rd := rt; + + when "010000" => --COP0 + alu_function := ALU_OR; + c_source := C_FROM_ALU; + if opcode(23) = '0' then --move from CP0 + rs := '1' & opcode(15 downto 11); + rt := "000000"; + rd := '0' & opcode(20 downto 16); + else --move to CP0 + rs := "000000"; + rd(5) := '1'; + pc_source := FROM_BRANCH; --delay possible interrupt + branch_function := BRANCH_NO; + end if; + + --when "010001" => --COP1 + --when "010010" => --COP2 + --when "010011" => --COP3 + --when "010100" => --BEQL lbranch=r[rs]==r[rt]; + --when "010101" => --BNEL lbranch=r[rs]!=r[rt]; + --when "010110" => --BLEZL lbranch=r[rs]<=0; + --when "010111" => --BGTZL lbranch=r[rs]>0; + + when "100000" => --LB r[rt]=*(signed char*)ptr; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + rd := rt; + c_source := C_FROM_MEMORY; + mem_source := MEM_READ8S; --address=(short)imm+r[rs]; + + when "100001" => --LH r[rt]=*(signed short*)ptr; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + rd := rt; + c_source := C_FROM_MEMORY; + mem_source := MEM_READ16S; --address=(short)imm+r[rs]; + + when "100010" => --LWL //Not Implemented + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + rd := rt; + c_source := C_FROM_MEMORY; + mem_source := MEM_READ32; + + when "100011" => --LW r[rt]=*(long*)ptr; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + rd := rt; + c_source := C_FROM_MEMORY; + mem_source := MEM_READ32; + + when "100100" => --LBU r[rt]=*(unsigned char*)ptr; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + rd := rt; + c_source := C_FROM_MEMORY; + mem_source := MEM_READ8; --address=(short)imm+r[rs]; + + when "100101" => --LHU r[rt]=*(unsigned short*)ptr; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + rd := rt; + c_source := C_FROM_MEMORY; + mem_source := MEM_READ16; --address=(short)imm+r[rs]; + + --when "100110" => --LWR //Not Implemented + + when "101000" => --SB *(char*)ptr=(char)r[rt]; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + mem_source := MEM_WRITE8; --address=(short)imm+r[rs]; + + when "101001" => --SH *(short*)ptr=(short)r[rt]; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + mem_source := MEM_WRITE16; + + when "101010" => --SWL //Not Implemented + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + mem_source := MEM_WRITE32; --address=(short)imm+r[rs]; + + when "101011" => --SW *(long*)ptr=r[rt]; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_SIGNED_IMM; + alu_function := ALU_ADD; + mem_source := MEM_WRITE32; --address=(short)imm+r[rs]; + + --when "101110" => --SWR //Not Implemented + --when "101111" => --CACHE + --when "110000" => --LL r[rt]=*(long*)ptr; + --when "110001" => --LWC1 + --when "110010" => --LWC2 + --when "110011" => --LWC3 + --when "110101" => --LDC1 + --when "110110" => --LDC2 + --when "110111" => --LDC3 + --when "111000" => --SC *(long*)ptr=r[rt]; r[rt]=1; + --when "111001" => --SWC1 + --when "111010" => --SWC2 + --when "111011" => --SWC3 + --when "111101" => --SDC1 + --when "111110" => --SDC2 + --when "111111" => --SDC3 + when others => + end case; + + if c_source = C_FROM_NULL then + rd := "000000"; + end if; + + if intr_signal = '1' or is_syscall = '1' then + rs := "111111"; --interrupt vector + rt := "000000"; + rd := "101110"; --save PC in EPC + alu_function := ALU_OR; + shift_function := SHIFT_NOTHING; + mult_function := MULT_NOTHING; + branch_function := BRANCH_YES; + a_source := A_FROM_REG_SOURCE; + b_source := B_FROM_REG_TARGET; + c_source := C_FROM_PC; + pc_source := FROM_LBRANCH; + mem_source := MEM_FETCH; + exception_out <= '1'; + else + exception_out <= '0'; + end if; + + rs_index <= rs; + rt_index <= rt; + rd_index <= rd; + imm_out <= imm; + alu_func <= alu_function; + shift_func <= shift_function; + mult_func <= mult_function; + branch_func <= branch_function; + a_source_out <= a_source; + b_source_out <= b_source; + c_source_out <= c_source; + pc_source_out <= pc_source; + mem_source_out <= mem_source; + +end process; + +end; --logic + diff --git a/vhdl/ddr_ctrl.vhd b/vhdl/ddr_ctrl.vhd new file mode 100644 index 0000000..34d84de --- /dev/null +++ b/vhdl/ddr_ctrl.vhd @@ -0,0 +1,354 @@ +--------------------------------------------------------------------- +-- TITLE: DDR SDRAM Interface +-- AUTHORS: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 7/26/07 +-- FILENAME: ddr_ctrl.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Double Data Rate Sychronous Dynamic Random Access Memory Interface +-- +-- For: 64 MB = MT46V32M16, 512Mb, 32Mb x 16 (default) +-- ROW = address(25 downto 13) +-- BANK = address(12 downto 11) +-- COL = address(10 downto 2) +-- +-- Changes are needed for 32 MB = MT46V16M16, 256Mb, 16Mb x 16 +-- ROW = address(24 downto 12) -- 25 ignored +-- BANK = address(11 downto 10) +-- COL = address(9 downto 2) --also change ddr_init.c +-- +-- Changes are needed for 128 MB = MT46V64M16, 1Gb, 64Mb x 16 +-- ROW = address(26 downto 14) +-- BANK = address(13 downto 12) +-- COL = address(11 downto 2) --also change ddr_init.c +-- +-- Requires CAS latency=2; burst size=2. +-- Requires clk changes on rising_edge(clk_2x). +-- Requires active, address, byte_we, data_w stable throughout transfer. +-- DLL mode requires 77MHz. Non-DLL mode runs at 25 MHz. +-- +-- cycle_cnt 777777770000111122223333444455556666777777777777 +-- clk_2x --__--__--__--__--__--__--__--__--__--__--__--__ +-- clk ____----____----____----____----____----____---- +-- SD_CLK ----____----____----____----____----____----____ +-- cmd ____write+++WRITE+++____________________________ +-- SD_DQ ~~~~~~~~~~~~~~uuuullllUUUULLLL~~~~~~~~~~~~~~~~~~ +-- +-- cycle_cnt 777777770000111122223333444455556666777777777777 +-- clk_2x --__--__--__--__--__--__--__--__--__--__--__--__ +-- clk ____----____----____----____----____----____---- +-- SD_CLK ----____----____----____----____----____----____ +-- cmd ____read++++________________________read++++____ +-- SD_DQ ~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~~~ +-- SD_DQnDLL ~~~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~ +-- pause ____------------------------________------------ +-- +-- Must run DdrInit() to initialize DDR chip. +-- Read Micron DDR SDRAM MT46V32M16 data sheet for more details. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; +use work.mlite_pack.all; + +entity ddr_ctrl is + port( + clk : in std_logic; + clk_2x : in std_logic; + reset_in : in std_logic; + + address : in std_logic_vector(25 downto 2); + byte_we : in std_logic_vector(3 downto 0); + data_w : in std_logic_vector(31 downto 0); + data_r : out std_logic_vector(31 downto 0); + active : in std_logic; + no_start : in std_logic; + no_stop : in std_logic; + pause : out std_logic; + + SD_CK_P : out std_logic; --clock_positive + SD_CK_N : out std_logic; --clock_negative + SD_CKE : out std_logic; --clock_enable + + SD_BA : out std_logic_vector(1 downto 0); --bank_address + SD_A : out std_logic_vector(12 downto 0); --address(row or col) + SD_CS : out std_logic; --chip_select + SD_RAS : out std_logic; --row_address_strobe + SD_CAS : out std_logic; --column_address_strobe + SD_WE : out std_logic; --write_enable + + SD_DQ : inout std_logic_vector(15 downto 0); --data + SD_UDM : out std_logic; --upper_byte_enable + SD_UDQS : inout std_logic; --upper_data_strobe + SD_LDM : out std_logic; --low_byte_enable + SD_LDQS : inout std_logic); --low_data_strobe +end; --entity ddr + +architecture logic of ddr_ctrl is + + --Commands for bits RAS & CAS & WE + subtype command_type is std_logic_vector(2 downto 0); + constant COMMAND_LMR : command_type := "000"; + constant COMMAND_AUTO_REFRESH : command_type := "001"; + constant COMMAND_PRECHARGE : command_type := "010"; + constant COMMAND_ACTIVE : command_type := "011"; + constant COMMAND_WRITE : command_type := "100"; + constant COMMAND_READ : command_type := "101"; + constant COMMAND_TERMINATE : command_type := "110"; + constant COMMAND_NOP : command_type := "111"; + + subtype ddr_state_type is std_logic_vector(3 downto 0); + constant STATE_POWER_ON : ddr_state_type := "0000"; + constant STATE_IDLE : ddr_state_type := "0001"; + constant STATE_ROW_ACTIVATE : ddr_state_type := "0010"; + constant STATE_ROW_ACTIVE : ddr_state_type := "0011"; + constant STATE_READ : ddr_state_type := "0100"; + constant STATE_READ2 : ddr_state_type := "0101"; + constant STATE_READ3 : ddr_state_type := "0110"; + constant STATE_PRECHARGE : ddr_state_type := "0111"; + constant STATE_PRECHARGE2 : ddr_state_type := "1000"; + + signal state_prev : ddr_state_type; + signal refresh_cnt : std_logic_vector(7 downto 0); + signal data_write2 : std_logic_vector(47 downto 0); --write pipeline + signal byte_we_reg2 : std_logic_vector(5 downto 0); --write pipeline + signal write_active : std_logic; + signal write_prev : std_logic; + signal cycle_count : std_logic_vector(2 downto 0); --half clocks since op + signal cycle_count2 : std_logic_vector(2 downto 0); --delayed by quarter clock + signal cke_reg : std_logic; + signal clk_p : std_logic; + signal bank_open : std_logic_vector(3 downto 0); + signal data_read : std_logic_vector(31 downto 0); + +begin + ddr_proc: process(clk, clk_p, clk_2x, reset_in, + address, byte_we, data_w, active, no_start, no_stop, + SD_DQ, SD_UDQS, SD_LDQS, + state_prev, refresh_cnt, + byte_we_reg2, data_write2, + cycle_count, cycle_count2, write_prev, + write_active, cke_reg, bank_open, + data_read) + type address_array_type is array(3 downto 0) of std_logic_vector(12 downto 0); + variable address_row : address_array_type; + variable command : std_logic_vector(2 downto 0); --RAS & CAS & WE + variable bank_index : integer; + variable state_current : ddr_state_type; + + begin + + command := COMMAND_NOP; + bank_index := conv_integer(address(12 downto 11)); + state_current := state_prev; + + --DDR state machine to determine state_current and command + case state_prev is + when STATE_POWER_ON => + if active = '1' then + if byte_we /= "0000" then + command := address(6 downto 4); --LMR="000" + else + state_current := STATE_IDLE; --read transistions to STATE_IDLE + end if; + end if; + + when STATE_IDLE => + if refresh_cnt(7) = '1' then + state_current := STATE_PRECHARGE; + command := COMMAND_AUTO_REFRESH; + elsif active = '1' and no_start = '0' then + state_current := STATE_ROW_ACTIVATE; + command := COMMAND_ACTIVE; + end if; + + when STATE_ROW_ACTIVATE => + state_current := STATE_ROW_ACTIVE; + + when STATE_ROW_ACTIVE => + if refresh_cnt(7) = '1' then + if write_prev = '0' then + state_current := STATE_PRECHARGE; + command := COMMAND_PRECHARGE; + end if; + elsif active = '1' and no_start = '0' then + if bank_open(bank_index) = '0' then + state_current := STATE_ROW_ACTIVATE; + command := COMMAND_ACTIVE; + elsif address(25 downto 13) /= address_row(bank_index) then + if write_prev = '0' then + state_current := STATE_PRECHARGE; + command := COMMAND_PRECHARGE; + end if; + else + if byte_we /= "0000" then + command := COMMAND_WRITE; + elsif write_prev = '0' then + state_current := STATE_READ; + command := COMMAND_READ; + end if; + end if; + end if; + + when STATE_READ => + state_current := STATE_READ2; + + when STATE_READ2 => + state_current := STATE_READ3; + + when STATE_READ3 => + if no_stop = '0' then + state_current := STATE_ROW_ACTIVE; + end if; + + when STATE_PRECHARGE => + state_current := STATE_PRECHARGE2; + + when STATE_PRECHARGE2 => + state_current := STATE_IDLE; + + when others => + state_current := STATE_IDLE; + end case; --state_prev + + --rising_edge(clk) domain registers + if reset_in = '1' then + state_prev <= STATE_POWER_ON; + cke_reg <= '0'; + refresh_cnt <= ZERO(7 downto 0); + write_prev <= '0'; + write_active <= '0'; + bank_open <= "0000"; + elsif rising_edge(clk) then + + if active = '1' then + cke_reg <= '1'; + end if; + + if command = COMMAND_WRITE then + write_prev <= '1'; + elsif cycle_count2(2 downto 1) = "11" then + write_prev <= '0'; + end if; + + if command = COMMAND_WRITE then + write_active <= '1'; + elsif cycle_count2 = "100" then + write_active <= '0'; + end if; + + if command = COMMAND_ACTIVE then + bank_open(bank_index) <= '1'; + address_row(bank_index) := address(25 downto 13); + end if; + + if command = COMMAND_PRECHARGE then + bank_open <= "0000"; + end if; + + if command = COMMAND_AUTO_REFRESH then + refresh_cnt <= ZERO(7 downto 0); + else + refresh_cnt <= refresh_cnt + 1; + end if; + + state_prev <= state_current; + + end if; --rising_edge(clk) + + --rising_edge(clk_2x) domain registers + if reset_in = '1' then + cycle_count <= "000"; + elsif rising_edge(clk_2x) then + --Cycle_count + if (command = COMMAND_READ or command = COMMAND_WRITE) and clk = '1' then + cycle_count <= "000"; + elsif cycle_count /= "111" then + cycle_count <= cycle_count + 1; + end if; + + clk_p <= clk; --earlier version of not clk + + --Read data (DLL disabled) + if cycle_count = "100" then + data_read(31 downto 16) <= SD_DQ; --data + elsif cycle_count = "101" then + data_read(15 downto 0) <= SD_DQ; + end if; + end if; + + --falling_edge(clk_2x) domain registers + if reset_in = '1' then + cycle_count2 <= "000"; + data_write2 <= ZERO(15 downto 0) & ZERO; + byte_we_reg2 <= "000000"; + elsif falling_edge(clk_2x) then + cycle_count2 <= cycle_count; + + --Write pipeline + if clk = '0' then + data_write2 <= data_write2(31 downto 16) & data_w; + byte_we_reg2 <= byte_we_reg2(3 downto 2) & byte_we; + else + data_write2(47 downto 16) <= data_write2(31 downto 0); + byte_we_reg2(5 downto 2) <= byte_we_reg2(3 downto 0); + end if; + + --Read data (DLL enabled) + --if cycle_count = "100" then + -- data_read(31 downto 16) <= SD_DQ; --data + --elsif cycle_count = "101" then + -- data_read(15 downto 0) <= SD_DQ; + --end if; + end if; + + data_r <= data_read; + + --Write data + if write_active = '1' then + SD_UDQS <= clk_p; --upper_data_strobe + SD_LDQS <= clk_p; --low_data_strobe + SD_DQ <= data_write2(47 downto 32); --data + SD_UDM <= not byte_we_reg2(5); --upper_byte_enable + SD_LDM <= not byte_we_reg2(4); --low_byte_enable + else + SD_UDQS <= 'Z'; --upper_data_strobe + SD_LDQS <= 'Z'; --low_data_strobe + SD_DQ <= "ZZZZZZZZZZZZZZZZ"; --data + SD_UDM <= 'Z'; + SD_LDM <= 'Z'; + end if; + + --DDR control signals + SD_CK_P <= clk_p; --clock_positive + SD_CK_N <= not clk_p; --clock_negative + SD_CKE <= cke_reg; --clock_enable + + SD_BA <= address(12 downto 11); --bank_address + if command = COMMAND_ACTIVE or state_current = STATE_POWER_ON then + SD_A <= address(25 downto 13); --address row + elsif command = COMMAND_READ or command = COMMAND_WRITE then + SD_A <= "000" & address(10 downto 2) & "0"; --address col + else + SD_A <= "0010000000000"; --PERCHARGE all banks + end if; + + SD_CS <= not cke_reg; --chip_select + SD_RAS <= command(2); --row_address_strobe + SD_CAS <= command(1); --column_address_strobe + SD_WE <= command(0); --write_enable + + if active = '1' and state_current /= STATE_POWER_ON and + command /= COMMAND_WRITE and state_prev /= STATE_READ3 then + pause <= '1'; + else + pause <= '0'; + end if; + + end process; --ddr_proc + +end; --architecture logic + diff --git a/vhdl/eth_dma.vhd b/vhdl/eth_dma.vhd new file mode 100644 index 0000000..227db86 --- /dev/null +++ b/vhdl/eth_dma.vhd @@ -0,0 +1,183 @@ +--------------------------------------------------------------------- +-- TITLE: Ethernet DMA +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 12/27/07 +-- FILENAME: eth_dma.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Ethernet DMA (Direct Memory Access) controller. +-- Reads four bits and writes four bits from/to the Ethernet PHY each +-- 2.5 MHz clock cycle. Received data is DMAed starting at 0x13ff0000 +-- transmit data is read from 0x13fd0000. +-- To send a packet write bytes/4 to Ethernet send register. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; +use work.mlite_pack.all; + +entity eth_dma is port( + clk : in std_logic; --25 MHz + reset : in std_logic; + enable_eth : in std_logic; --enable receive DMA + select_eth : in std_logic; + rec_isr : out std_logic; --data received + send_isr : out std_logic; --transmit done + + address : out std_logic_vector(31 downto 2); --to DDR + byte_we : out std_logic_vector(3 downto 0); + data_write : out std_logic_vector(31 downto 0); + data_read : in std_logic_vector(31 downto 0); + pause_in : in std_logic; + + mem_address : in std_logic_vector(31 downto 2); --from CPU + mem_byte_we : in std_logic_vector(3 downto 0); + data_w : in std_logic_vector(31 downto 0); + pause_out : out std_logic; + + E_RX_CLK : in std_logic; --2.5 MHz receive + E_RX_DV : in std_logic; --data valid + E_RXD : in std_logic_vector(3 downto 0); --receive nibble + E_TX_CLK : in std_logic; --2.5 MHz transmit + E_TX_EN : out std_logic; --transmit enable + E_TXD : out std_logic_vector(3 downto 0)); --transmit nibble +end; --entity eth_dma + +architecture logic of eth_dma is + signal rec_clk : std_logic_vector(1 downto 0); --receive + signal rec_store : std_logic_vector(31 downto 0); --to DDR + signal rec_data : std_logic_vector(27 downto 0); + signal rec_cnt : std_logic_vector(2 downto 0); --nibbles + signal rec_words : std_logic_vector(13 downto 0); + signal rec_dma : std_logic_vector(1 downto 0); --active & request + signal rec_done : std_logic; + + signal send_clk : std_logic_vector(1 downto 0); --transmit + signal send_read : std_logic_vector(31 downto 0); --from DDR + signal send_data : std_logic_vector(31 downto 0); + signal send_cnt : std_logic_vector(2 downto 0); --nibbles + signal send_words : std_logic_vector(8 downto 0); + signal send_level : std_logic_vector(8 downto 0); + signal send_dma : std_logic_vector(1 downto 0); --active & request + signal send_enable: std_logic; + +begin --architecture + + dma_proc: process(clk, reset, enable_eth, select_eth, + data_read, pause_in, mem_address, mem_byte_we, data_w, + E_RX_CLK, E_RX_DV, E_RXD, E_TX_CLK, + rec_clk, rec_store, rec_data, + rec_cnt, rec_words, rec_dma, rec_done, + send_clk, send_read, send_data, send_cnt, send_words, + send_level, send_dma, send_enable) + begin + + if reset = '1' then + rec_clk <= "00"; + rec_cnt <= "000"; + rec_words <= ZERO(13 downto 0); + rec_dma <= "00"; + rec_done <= '0'; + send_clk <= "00"; + send_cnt <= "000"; + send_words <= ZERO(8 downto 0); + send_level <= ZERO(8 downto 0); + send_dma <= "00"; + send_enable <= '0'; + elsif rising_edge(clk) then + + --Receive nibble on low->high E_RX_CLK. Send to DDR every 32 bits. + rec_clk <= rec_clk(0) & E_RX_CLK; + if rec_clk = "01" and enable_eth = '1' then + if E_RX_DV = '1' or rec_cnt /= "000" then + if rec_cnt = "111" then + rec_store <= rec_data & E_RXD; + rec_dma(0) <= '1'; --request DMA + end if; + rec_data <= rec_data(23 downto 0) & E_RXD; + rec_cnt <= rec_cnt + 1; + end if; + end if; + + --Set transmit count or clear receive interrupt + if select_eth = '1' then + if mem_byte_we /= "0000" then + send_cnt <= "000"; + send_words <= ZERO(8 downto 0); + send_level <= data_w(8 downto 0); + send_dma(0) <= '1'; + else + rec_done <= '0'; + end if; + end if; + + --Transmit nibble on low->high E_TX_CLK. Get 32 bits from DDR. + send_clk <= send_clk(0) & E_TX_CLK; + if send_clk = "01" then + if send_cnt = "111" then + if send_words /= send_level then + send_data <= send_read; + send_dma(0) <= '1'; + send_enable <= '1'; + else + send_enable <= '0'; + end if; + else + send_data(31 downto 4) <= send_data(27 downto 0); + end if; + send_cnt <= send_cnt + 1; + end if; + + --Pick which type of DMA operation: bit0 = request; bit1 = active + if pause_in = '0' then + if rec_dma(1) = '1' then + rec_dma <= "00"; --DMA done + rec_words <= rec_words + 1; + if E_RX_DV = '0' then + rec_done <= '1'; + end if; + elsif send_dma(1) = '1' then + send_dma <= "00"; + send_words <= send_words + 1; + send_read <= data_read; + elsif rec_dma(0) = '1' then + rec_dma(1) <= '1'; --start DMA + elsif send_dma(0) = '1' then + send_dma(1) <= '1'; --start DMA + end if; + end if; + + end if; --rising_edge(clk) + + E_TXD <= send_data(31 downto 28); + E_TX_EN <= send_enable; + rec_isr <= rec_done; + if send_words = send_level then + send_isr <= '1'; + else + send_isr <= '0'; + end if; + + if rec_dma(1) = '1' then + address <= "0001001111111111" & rec_words; --0x13ff0000 + byte_we <= "1111"; + data_write <= rec_store; + pause_out <= '1'; --to CPU + elsif send_dma(1) = '1' then + address <= "000100111111111000000" & send_words; --0x13fe0000 + byte_we <= "0000"; + data_write <= data_w; + pause_out <= '1'; + else + address <= mem_address; --Send request from CPU to DDR + byte_we <= mem_byte_we; + data_write <= data_w; + pause_out <= '0'; + end if; + + end process; + +end; --architecture logic diff --git a/vhdl/makefile b/vhdl/makefile new file mode 100644 index 0000000..0928ec9 --- /dev/null +++ b/vhdl/makefile @@ -0,0 +1,119 @@ +#Makefile for Plasma + +#for ModelSim +#WORK_DIR = work +#DEP_FILE = _primary.dat +#COMPILE = vcom -check_synthesis + +#for FREE VHDL simulator http://www.symphonyeda.com +#WARNING: vhdle now deletes the output.txt if terminated by a ^C +WORK_DIR = work.sym +DEP_FILE = prim.dep +COMPILE = vhdlp -s + +all: $(WORK_DIR)/tbench/$(DEP_FILE) + +run: all + -@del output.txt + vhdle -t 30us tbench + type output.txt|more + +run2: all + -@del output.txt + vhdle -t 50us tbench + type output.txt|more + +run3: all + -@del output.txt + vhdle -t 100us tbench + type output.txt|more + +opcodes: all + make -C ..\tools opcodes + vhdle -t 200us tbench + @type output.txt|more + +simulate: all + vhdle -s -t 10us tbench -do simili.cmd -list trace.txt + -@..\tools\tracehex.exe + -@start ed trace2.txt + +simulate2: all + vhdle -s -t 4us tbench -do simili.cmd -list trace.txt + -@..\tools\tracehex.exe + -@ed trace2.txt + +$(WORK_DIR)/lpm_pack/$(DEP_FILE): lpm_pack.vhd + $(COMPILE) lpm_pack.vhd + +$(WORK_DIR)/lpm_model/$(DEP_FILE): lpm_model.vhd + $(COMPILE) -87 lpm_model.vhd + +$(WORK_DIR)/mlite_pack/$(DEP_FILE): mlite_pack.vhd + $(COMPILE) mlite_pack.vhd + +$(WORK_DIR)/alu/$(DEP_FILE): mlite_pack.vhd alu.vhd + $(COMPILE) alu.vhd + +$(WORK_DIR)/bus_mux/$(DEP_FILE): mlite_pack.vhd bus_mux.vhd + $(COMPILE) bus_mux.vhd + +$(WORK_DIR)/control/$(DEP_FILE): mlite_pack.vhd control.vhd + $(COMPILE) control.vhd + +$(WORK_DIR)/mem_ctrl/$(DEP_FILE): mlite_pack.vhd mem_ctrl.vhd + $(COMPILE) mem_ctrl.vhd + +$(WORK_DIR)/mult/$(DEP_FILE): mlite_pack.vhd mult.vhd + $(COMPILE) mult.vhd + +$(WORK_DIR)/pc_next/$(DEP_FILE): mlite_pack.vhd pc_next.vhd + $(COMPILE) pc_next.vhd + +$(WORK_DIR)/reg_bank/$(DEP_FILE): mlite_pack.vhd reg_bank.vhd + $(COMPILE) reg_bank.vhd + +$(WORK_DIR)/shifter/$(DEP_FILE): mlite_pack.vhd shifter.vhd + $(COMPILE) shifter.vhd + +$(WORK_DIR)/pipeline/$(DEP_FILE): mlite_pack.vhd pipeline.vhd + $(COMPILE) pipeline.vhd + +$(WORK_DIR)/mlite_cpu/$(DEP_FILE): mlite_cpu.vhd \ + $(WORK_DIR)/mlite_pack/$(DEP_FILE) \ + $(WORK_DIR)/alu/$(DEP_FILE) \ + $(WORK_DIR)/bus_mux/$(DEP_FILE) \ + $(WORK_DIR)/control/$(DEP_FILE) \ + $(WORK_DIR)/mem_ctrl/$(DEP_FILE) \ + $(WORK_DIR)/mult/$(DEP_FILE) \ + $(WORK_DIR)/pc_next/$(DEP_FILE) \ + $(WORK_DIR)/reg_bank/$(DEP_FILE) \ + $(WORK_DIR)/shifter/$(DEP_FILE) \ + $(WORK_DIR)/pipeline/$(DEP_FILE) + $(COMPILE) mlite_cpu.vhd + +$(WORK_DIR)/ram/$(DEP_FILE): mlite_pack.vhd ram.vhd + $(COMPILE) -87 ram.vhd + +$(WORK_DIR)/uart/$(DEP_FILE): mlite_pack.vhd uart.vhd + $(COMPILE) -87 uart.vhd + +$(WORK_DIR)/plasma/$(DEP_FILE): mlite_pack.vhd plasma.vhd \ + $(WORK_DIR)/mlite_cpu/$(DEP_FILE) \ + $(WORK_DIR)/ram/$(DEP_FILE) \ + $(WORK_DIR)/uart/$(DEP_FILE) + $(COMPILE) plasma.vhd + +$(WORK_DIR)/plasma_if/$(DEP_FILE): mlite_pack.vhd plasma_if.vhd \ + $(WORK_DIR)/plasma/$(DEP_FILE) + $(COMPILE) plasma_if.vhd + +$(WORK_DIR)/tbench/$(DEP_FILE): mlite_pack.vhd tbench.vhd \ + $(WORK_DIR)/plasma/$(DEP_FILE) \ + $(WORK_DIR)/plasma_if/$(DEP_FILE) + $(COMPILE) tbench.vhd + +altera: $(WORK_DIR)/lpm_pack/$(DEP_FILE) \ + $(WORK_DIR)/lpm_model/$(DEP_FILE) + echo UNUSED > UNUSED + diff --git a/vhdl/mem_ctrl.vhd b/vhdl/mem_ctrl.vhd new file mode 100644 index 0000000..8188f03 --- /dev/null +++ b/vhdl/mem_ctrl.vhd @@ -0,0 +1,196 @@ +--------------------------------------------------------------------- +-- TITLE: Memory Controller +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 1/31/01 +-- FILENAME: mem_ctrl.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Memory controller for the Plasma CPU. +-- Supports Big or Little Endian mode. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; + +entity mem_ctrl is + port(clk : in std_logic; + reset_in : in std_logic; + pause_in : in std_logic; + nullify_op : in std_logic; + address_pc : in std_logic_vector(31 downto 2); + opcode_out : out std_logic_vector(31 downto 0); + + address_in : in std_logic_vector(31 downto 0); + mem_source : in mem_source_type; + data_write : in std_logic_vector(31 downto 0); + data_read : out std_logic_vector(31 downto 0); + pause_out : out std_logic; + + address_next : out std_logic_vector(31 downto 2); + byte_we_next : out std_logic_vector(3 downto 0); + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_w : out std_logic_vector(31 downto 0); + data_r : in std_logic_vector(31 downto 0)); +end; --entity mem_ctrl + +architecture logic of mem_ctrl is + --"00" = big_endian; "11" = little_endian + constant ENDIAN_MODE : std_logic_vector(1 downto 0) := "00"; + signal opcode_reg : std_logic_vector(31 downto 0); + signal next_opcode_reg : std_logic_vector(31 downto 0); + signal address_reg : std_logic_vector(31 downto 2); + signal byte_we_reg : std_logic_vector(3 downto 0); + + signal mem_state_reg : std_logic; + constant STATE_ADDR : std_logic := '0'; + constant STATE_ACCESS : std_logic := '1'; + +begin + +mem_proc: process(clk, reset_in, pause_in, nullify_op, + address_pc, address_in, mem_source, data_write, + data_r, opcode_reg, next_opcode_reg, mem_state_reg, + address_reg, byte_we_reg) + variable address_var : std_logic_vector(31 downto 2); + variable data_read_var : std_logic_vector(31 downto 0); + variable data_write_var : std_logic_vector(31 downto 0); + variable opcode_next : std_logic_vector(31 downto 0); + variable byte_we_var : std_logic_vector(3 downto 0); + variable mem_state_next : std_logic; + variable pause_var : std_logic; + variable bits : std_logic_vector(1 downto 0); +begin + byte_we_var := "0000"; + pause_var := '0'; + data_read_var := ZERO; + data_write_var := ZERO; + mem_state_next := mem_state_reg; + opcode_next := opcode_reg; + + case mem_source is + when MEM_READ32 => + data_read_var := data_r; + + when MEM_READ16 | MEM_READ16S => + if address_in(1) = ENDIAN_MODE(1) then + data_read_var(15 downto 0) := data_r(31 downto 16); + else + data_read_var(15 downto 0) := data_r(15 downto 0); + end if; + if mem_source = MEM_READ16 or data_read_var(15) = '0' then + data_read_var(31 downto 16) := ZERO(31 downto 16); + else + data_read_var(31 downto 16) := ONES(31 downto 16); + end if; + + when MEM_READ8 | MEM_READ8S => + bits := address_in(1 downto 0) xor ENDIAN_MODE; + case bits is + when "00" => data_read_var(7 downto 0) := data_r(31 downto 24); + when "01" => data_read_var(7 downto 0) := data_r(23 downto 16); + when "10" => data_read_var(7 downto 0) := data_r(15 downto 8); + when others => data_read_var(7 downto 0) := data_r(7 downto 0); + end case; + if mem_source = MEM_READ8 or data_read_var(7) = '0' then + data_read_var(31 downto 8) := ZERO(31 downto 8); + else + data_read_var(31 downto 8) := ONES(31 downto 8); + end if; + + when MEM_WRITE32 => + data_write_var := data_write; + byte_we_var := "1111"; + + when MEM_WRITE16 => + data_write_var := data_write(15 downto 0) & data_write(15 downto 0); + if address_in(1) = ENDIAN_MODE(1) then + byte_we_var := "1100"; + else + byte_we_var := "0011"; + end if; + + when MEM_WRITE8 => + data_write_var := data_write(7 downto 0) & data_write(7 downto 0) & + data_write(7 downto 0) & data_write(7 downto 0); + bits := address_in(1 downto 0) xor ENDIAN_MODE; + case bits is + when "00" => + byte_we_var := "1000"; + when "01" => + byte_we_var := "0100"; + when "10" => + byte_we_var := "0010"; + when others => + byte_we_var := "0001"; + end case; + + when others => + end case; + + if mem_source = MEM_FETCH then --opcode fetch + address_var := address_pc; + opcode_next := data_r; + mem_state_next := STATE_ADDR; + else + if mem_state_reg = STATE_ADDR then + if pause_in = '0' then + address_var := address_in(31 downto 2); + mem_state_next := STATE_ACCESS; + pause_var := '1'; + else + address_var := address_pc; + byte_we_var := "0000"; + end if; + else --STATE_ACCESS + if pause_in = '0' then + address_var := address_pc; + opcode_next := next_opcode_reg; + mem_state_next := STATE_ADDR; + byte_we_var := "0000"; + else + address_var := address_in(31 downto 2); + byte_we_var := "0000"; + end if; + end if; + end if; + + if nullify_op = '1' and pause_in = '0' then + opcode_next := ZERO; --NOP after beql + end if; + + if reset_in = '1' then + mem_state_reg <= STATE_ADDR; + opcode_reg <= ZERO; + next_opcode_reg <= ZERO; + address_reg <= ZERO(31 downto 2); + byte_we_reg <= "0000"; + elsif rising_edge(clk) then + if pause_in = '0' then + address_reg <= address_var; + byte_we_reg <= byte_we_var; + mem_state_reg <= mem_state_next; + opcode_reg <= opcode_next; + if mem_state_reg = STATE_ADDR then + next_opcode_reg <= data_r; + end if; + end if; + end if; + + opcode_out <= opcode_reg; + data_read <= data_read_var; + pause_out <= pause_var; + + address_next <= address_var; + byte_we_next <= byte_we_var; + + address <= address_reg; + byte_we <= byte_we_reg; + data_w <= data_write_var; + +end process; --data_proc + +end; --architecture logic diff --git a/vhdl/mlite_cpu.vhd b/vhdl/mlite_cpu.vhd new file mode 100644 index 0000000..c512661 --- /dev/null +++ b/vhdl/mlite_cpu.vhd @@ -0,0 +1,342 @@ +--------------------------------------------------------------------- +-- TITLE: Plasma CPU core +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/15/01 +-- FILENAME: mlite_cpu.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- NOTE: MIPS(tm) and MIPS I(tm) are registered trademarks of MIPS +-- Technologies. MIPS Technologies does not endorse and is not +-- associated with this project. +-- DESCRIPTION: +-- Top level VHDL document that ties the nine other entities together. +-- +-- Executes all MIPS I(tm) opcodes but exceptions and non-aligned +-- memory accesses. Based on information found in: +-- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich +-- and "The Designer's Guide to VHDL" by Peter J. Ashenden +-- +-- The CPU is implemented as a two or three stage pipeline. +-- An add instruction would take the following steps (see cpu.gif): +-- Stage #0: +-- 1. The "pc_next" entity passes the program counter (PC) to the +-- "mem_ctrl" entity which fetches the opcode from memory. +-- Stage #1: +-- 2. The memory returns the opcode. +-- Stage #2: +-- 3. "Mem_ctrl" passes the opcode to the "control" entity. +-- 4. "Control" converts the 32-bit opcode to a 60-bit VLWI opcode +-- and sends control signals to the other entities. +-- 5. Based on the rs_index and rt_index control signals, "reg_bank" +-- sends the 32-bit reg_source and reg_target to "bus_mux". +-- 6. Based on the a_source and b_source control signals, "bus_mux" +-- multiplexes reg_source onto a_bus and reg_target onto b_bus. +-- Stage #3 (part of stage #2 if using two stage pipeline): +-- 7. Based on the alu_func control signals, "alu" adds the values +-- from a_bus and b_bus and places the result on c_bus. +-- 8. Based on the c_source control signals, "bus_bux" multiplexes +-- c_bus onto reg_dest. +-- 9. Based on the rd_index control signal, "reg_bank" saves +-- reg_dest into the correct register. +-- Stage #3b: +-- 10. Read or write memory if needed. +-- +-- All signals are active high. +-- Here are the signals for writing a character to address 0xffff +-- when using a two stage pipeline: +-- +-- Program: +-- addr value opcode +-- ============================= +-- 3c: 00000000 nop +-- 40: 34040041 li $a0,0x41 +-- 44: 3405ffff li $a1,0xffff +-- 48: a0a40000 sb $a0,0($a1) +-- 4c: 00000000 nop +-- 50: 00000000 nop +-- +-- intr_in mem_pause +-- reset_in byte_we Stages +-- ns address data_w data_r 40 44 48 4c 50 +-- 3600 0 0 00000040 00000000 34040041 0 0 1 +-- 3700 0 0 00000044 00000000 3405FFFF 0 0 2 1 +-- 3800 0 0 00000048 00000000 A0A40000 0 0 2 1 +-- 3900 0 0 0000004C 41414141 00000000 0 0 2 1 +-- 4000 0 0 0000FFFC 41414141 XXXXXX41 1 0 3 2 +-- 4100 0 0 00000050 00000000 00000000 0 0 1 +--------------------------------------------------------------------- +library ieee; +use work.mlite_pack.all; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity mlite_cpu is + generic(memory_type : string := "XILINX_16X"; --ALTERA_LPM, or DUAL_PORT_ + mult_type : string := "DEFAULT"; --AREA_OPTIMIZED + shifter_type : string := "DEFAULT"; --AREA_OPTIMIZED + alu_type : string := "DEFAULT"; --AREA_OPTIMIZED + pipeline_stages : natural := 2); --2 or 3 + port(clk : in std_logic; + reset_in : in std_logic; + intr_in : in std_logic; + + address_next : out std_logic_vector(31 downto 2); --for synch ram + byte_we_next : out std_logic_vector(3 downto 0); + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_w : out std_logic_vector(31 downto 0); + data_r : in std_logic_vector(31 downto 0); + mem_pause : in std_logic); +end; --entity mlite_cpu + +architecture logic of mlite_cpu is + --When using a two stage pipeline "sigD <= sig". + --When using a three stage pipeline "sigD <= sig when rising_edge(clk)", + -- so sigD is delayed by one clock cycle. + signal opcode : std_logic_vector(31 downto 0); + signal rs_index : std_logic_vector(5 downto 0); + signal rt_index : std_logic_vector(5 downto 0); + signal rd_index : std_logic_vector(5 downto 0); + signal rd_indexD : std_logic_vector(5 downto 0); + signal reg_source : std_logic_vector(31 downto 0); + signal reg_target : std_logic_vector(31 downto 0); + signal reg_dest : std_logic_vector(31 downto 0); + signal reg_destD : std_logic_vector(31 downto 0); + signal a_bus : std_logic_vector(31 downto 0); + signal a_busD : std_logic_vector(31 downto 0); + signal b_bus : std_logic_vector(31 downto 0); + signal b_busD : std_logic_vector(31 downto 0); + signal c_bus : std_logic_vector(31 downto 0); + signal c_alu : std_logic_vector(31 downto 0); + signal c_shift : std_logic_vector(31 downto 0); + signal c_mult : std_logic_vector(31 downto 0); + signal c_memory : std_logic_vector(31 downto 0); + signal imm : std_logic_vector(15 downto 0); + signal pc_future : std_logic_vector(31 downto 2); + signal pc_current : std_logic_vector(31 downto 2); + signal pc_plus4 : std_logic_vector(31 downto 2); + signal alu_func : alu_function_type; + signal alu_funcD : alu_function_type; + signal shift_func : shift_function_type; + signal shift_funcD : shift_function_type; + signal mult_func : mult_function_type; + signal mult_funcD : mult_function_type; + signal branch_func : branch_function_type; + signal take_branch : std_logic; + signal a_source : a_source_type; + signal b_source : b_source_type; + signal c_source : c_source_type; + signal pc_source : pc_source_type; + signal mem_source : mem_source_type; + signal pause_mult : std_logic; + signal pause_ctrl : std_logic; + signal pause_pipeline : std_logic; + signal pause_any : std_logic; + signal pause_non_ctrl : std_logic; + signal pause_bank : std_logic; + signal nullify_op : std_logic; + signal intr_enable : std_logic; + signal intr_signal : std_logic; + signal exception_sig : std_logic; + signal reset_reg : std_logic_vector(3 downto 0); + signal reset : std_logic; +begin --architecture + + pause_any <= (mem_pause or pause_ctrl) or (pause_mult or pause_pipeline); + pause_non_ctrl <= (mem_pause or pause_mult) or pause_pipeline; + pause_bank <= (mem_pause or pause_ctrl or pause_mult) and not pause_pipeline; + nullify_op <= '1' when (pc_source = FROM_LBRANCH and take_branch = '0') + or intr_signal = '1' or exception_sig = '1' + else '0'; + c_bus <= c_alu or c_shift or c_mult; + reset <= '1' when reset_in = '1' or reset_reg /= "1111" else '0'; + + --synchronize reset and interrupt pins + intr_proc: process(clk, reset_in, reset_reg, intr_in, intr_enable, + pc_source, pc_current, pause_any) + begin + if reset_in = '1' then + reset_reg <= "0000"; + intr_signal <= '0'; + elsif rising_edge(clk) then + if reset_reg /= "1111" then + reset_reg <= reset_reg + 1; + end if; + + --don't try to interrupt a multi-cycle instruction + if pause_any = '0' then + if intr_in = '1' and intr_enable = '1' and + pc_source = FROM_INC4 then + --the epc will contain pc+4 + intr_signal <= '1'; + else + intr_signal <= '0'; + end if; + end if; + + end if; + end process; + + u1_pc_next: pc_next PORT MAP ( + clk => clk, + reset_in => reset, + take_branch => take_branch, + pause_in => pause_any, + pc_new => c_bus(31 downto 2), + opcode25_0 => opcode(25 downto 0), + pc_source => pc_source, + pc_future => pc_future, + pc_current => pc_current, + pc_plus4 => pc_plus4); + + u2_mem_ctrl: mem_ctrl + PORT MAP ( + clk => clk, + reset_in => reset, + pause_in => pause_non_ctrl, + nullify_op => nullify_op, + address_pc => pc_future, + opcode_out => opcode, + + address_in => c_bus, + mem_source => mem_source, + data_write => reg_target, + data_read => c_memory, + pause_out => pause_ctrl, + + address_next => address_next, + byte_we_next => byte_we_next, + + address => address, + byte_we => byte_we, + data_w => data_w, + data_r => data_r); + + u3_control: control PORT MAP ( + opcode => opcode, + intr_signal => intr_signal, + rs_index => rs_index, + rt_index => rt_index, + rd_index => rd_index, + imm_out => imm, + alu_func => alu_func, + shift_func => shift_func, + mult_func => mult_func, + branch_func => branch_func, + a_source_out => a_source, + b_source_out => b_source, + c_source_out => c_source, + pc_source_out=> pc_source, + mem_source_out=> mem_source, + exception_out=> exception_sig); + + u4_reg_bank: reg_bank + generic map(memory_type => memory_type) + port map ( + clk => clk, + reset_in => reset, + pause => pause_bank, + rs_index => rs_index, + rt_index => rt_index, + rd_index => rd_indexD, + reg_source_out => reg_source, + reg_target_out => reg_target, + reg_dest_new => reg_destD, + intr_enable => intr_enable); + + u5_bus_mux: bus_mux port map ( + imm_in => imm, + reg_source => reg_source, + a_mux => a_source, + a_out => a_bus, + + reg_target => reg_target, + b_mux => b_source, + b_out => b_bus, + + c_bus => c_bus, + c_memory => c_memory, + c_pc => pc_current, + c_pc_plus4 => pc_plus4, + c_mux => c_source, + reg_dest_out => reg_dest, + + branch_func => branch_func, + take_branch => take_branch); + + u6_alu: alu + generic map (alu_type => alu_type) + port map ( + a_in => a_busD, + b_in => b_busD, + alu_function => alu_funcD, + c_alu => c_alu); + + u7_shifter: shifter + generic map (shifter_type => shifter_type) + port map ( + value => b_busD, + shift_amount => a_busD(4 downto 0), + shift_func => shift_funcD, + c_shift => c_shift); + + u8_mult: mult + generic map (mult_type => mult_type) + port map ( + clk => clk, + reset_in => reset, + a => a_busD, + b => b_busD, + mult_func => mult_funcD, + c_mult => c_mult, + pause_out => pause_mult); + + pipeline2: if pipeline_stages <= 2 generate + a_busD <= a_bus; + b_busD <= b_bus; + alu_funcD <= alu_func; + shift_funcD <= shift_func; + mult_funcD <= mult_func; + rd_indexD <= rd_index; + reg_destD <= reg_dest; + pause_pipeline <= '0'; + end generate; --pipeline2 + + pipeline3: if pipeline_stages > 2 generate + --When operating in three stage pipeline mode, the following signals + --are delayed by one clock cycle: a_bus, b_bus, alu/shift/mult_func, + --c_source, and rd_index. + u9_pipeline: pipeline port map ( + clk => clk, + reset => reset, + a_bus => a_bus, + a_busD => a_busD, + b_bus => b_bus, + b_busD => b_busD, + alu_func => alu_func, + alu_funcD => alu_funcD, + shift_func => shift_func, + shift_funcD => shift_funcD, + mult_func => mult_func, + mult_funcD => mult_funcD, + reg_dest => reg_dest, + reg_destD => reg_destD, + rd_index => rd_index, + rd_indexD => rd_indexD, + + rs_index => rs_index, + rt_index => rt_index, + pc_source => pc_source, + mem_source => mem_source, + a_source => a_source, + b_source => b_source, + c_source => c_source, + c_bus => c_bus, + pause_any => pause_any, + pause_pipeline => pause_pipeline); + + end generate; --pipeline3 + +end; --architecture logic diff --git a/vhdl/mlite_pack.vhd b/vhdl/mlite_pack.vhd new file mode 100644 index 0000000..f6e37a6 --- /dev/null +++ b/vhdl/mlite_pack.vhd @@ -0,0 +1,563 @@ +--------------------------------------------------------------------- +-- TITLE: Plasma Misc. Package +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/15/01 +-- FILENAME: mlite_pack.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Data types, constants, and add functions needed for the Plasma CPU. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; + +package mlite_pack is + constant ZERO : std_logic_vector(31 downto 0) := + "00000000000000000000000000000000"; + constant ONES : std_logic_vector(31 downto 0) := + "11111111111111111111111111111111"; + --make HIGH_Z equal to ZERO if compiler complains + constant HIGH_Z : std_logic_vector(31 downto 0) := + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; + + subtype alu_function_type is std_logic_vector(3 downto 0); + constant ALU_NOTHING : alu_function_type := "0000"; + constant ALU_ADD : alu_function_type := "0001"; + constant ALU_SUBTRACT : alu_function_type := "0010"; + constant ALU_LESS_THAN : alu_function_type := "0011"; + constant ALU_LESS_THAN_SIGNED : alu_function_type := "0100"; + constant ALU_OR : alu_function_type := "0101"; + constant ALU_AND : alu_function_type := "0110"; + constant ALU_XOR : alu_function_type := "0111"; + constant ALU_NOR : alu_function_type := "1000"; + + subtype shift_function_type is std_logic_vector(1 downto 0); + constant SHIFT_NOTHING : shift_function_type := "00"; + constant SHIFT_LEFT_UNSIGNED : shift_function_type := "01"; + constant SHIFT_RIGHT_SIGNED : shift_function_type := "11"; + constant SHIFT_RIGHT_UNSIGNED : shift_function_type := "10"; + + subtype mult_function_type is std_logic_vector(3 downto 0); + constant MULT_NOTHING : mult_function_type := "0000"; + constant MULT_READ_LO : mult_function_type := "0001"; + constant MULT_READ_HI : mult_function_type := "0010"; + constant MULT_WRITE_LO : mult_function_type := "0011"; + constant MULT_WRITE_HI : mult_function_type := "0100"; + constant MULT_MULT : mult_function_type := "0101"; + constant MULT_SIGNED_MULT : mult_function_type := "0110"; + constant MULT_DIVIDE : mult_function_type := "0111"; + constant MULT_SIGNED_DIVIDE : mult_function_type := "1000"; + + subtype a_source_type is std_logic_vector(1 downto 0); + constant A_FROM_REG_SOURCE : a_source_type := "00"; + constant A_FROM_IMM10_6 : a_source_type := "01"; + constant A_FROM_PC : a_source_type := "10"; + + subtype b_source_type is std_logic_vector(1 downto 0); + constant B_FROM_REG_TARGET : b_source_type := "00"; + constant B_FROM_IMM : b_source_type := "01"; + constant B_FROM_SIGNED_IMM : b_source_type := "10"; + constant B_FROM_IMMX4 : b_source_type := "11"; + + subtype c_source_type is std_logic_vector(2 downto 0); + constant C_FROM_NULL : c_source_type := "000"; + constant C_FROM_ALU : c_source_type := "001"; + constant C_FROM_SHIFT : c_source_type := "001"; --same as alu + constant C_FROM_MULT : c_source_type := "001"; --same as alu + constant C_FROM_MEMORY : c_source_type := "010"; + constant C_FROM_PC : c_source_type := "011"; + constant C_FROM_PC_PLUS4 : c_source_type := "100"; + constant C_FROM_IMM_SHIFT16: c_source_type := "101"; + constant C_FROM_REG_SOURCEN: c_source_type := "110"; + + subtype pc_source_type is std_logic_vector(1 downto 0); + constant FROM_INC4 : pc_source_type := "00"; + constant FROM_OPCODE25_0 : pc_source_type := "01"; + constant FROM_BRANCH : pc_source_type := "10"; + constant FROM_LBRANCH : pc_source_type := "11"; + + subtype branch_function_type is std_logic_vector(2 downto 0); + constant BRANCH_LTZ : branch_function_type := "000"; + constant BRANCH_LEZ : branch_function_type := "001"; + constant BRANCH_EQ : branch_function_type := "010"; + constant BRANCH_NE : branch_function_type := "011"; + constant BRANCH_GEZ : branch_function_type := "100"; + constant BRANCH_GTZ : branch_function_type := "101"; + constant BRANCH_YES : branch_function_type := "110"; + constant BRANCH_NO : branch_function_type := "111"; + + -- mode(32=1,16=2,8=3), signed, write + subtype mem_source_type is std_logic_vector(3 downto 0); + constant MEM_FETCH : mem_source_type := "0000"; + constant MEM_READ32 : mem_source_type := "0100"; + constant MEM_WRITE32 : mem_source_type := "0101"; + constant MEM_READ16 : mem_source_type := "1000"; + constant MEM_READ16S : mem_source_type := "1010"; + constant MEM_WRITE16 : mem_source_type := "1001"; + constant MEM_READ8 : mem_source_type := "1100"; + constant MEM_READ8S : mem_source_type := "1110"; + constant MEM_WRITE8 : mem_source_type := "1101"; + + function bv_adder(a : in std_logic_vector; + b : in std_logic_vector; + do_add: in std_logic) return std_logic_vector; + function bv_negate(a : in std_logic_vector) return std_logic_vector; + function bv_increment(a : in std_logic_vector(31 downto 2) + ) return std_logic_vector; + function bv_inc(a : in std_logic_vector + ) return std_logic_vector; + + -- For Altera + COMPONENT lpm_ram_dp + generic ( + LPM_WIDTH : natural; -- MUST be greater than 0 + LPM_WIDTHAD : natural; -- MUST be greater than 0 + LPM_NUMWORDS : natural := 0; + LPM_INDATA : string := "REGISTERED"; + LPM_OUTDATA : string := "REGISTERED"; + LPM_RDADDRESS_CONTROL : string := "REGISTERED"; + LPM_WRADDRESS_CONTROL : string := "REGISTERED"; + LPM_FILE : string := "UNUSED"; + LPM_TYPE : string := "LPM_RAM_DP"; + USE_EAB : string := "OFF"; + INTENDED_DEVICE_FAMILY : string := "UNUSED"; + RDEN_USED : string := "TRUE"; + LPM_HINT : string := "UNUSED"); + port ( + RDCLOCK : in std_logic := '0'; + RDCLKEN : in std_logic := '1'; + RDADDRESS : in std_logic_vector(LPM_WIDTHAD-1 downto 0); + RDEN : in std_logic := '1'; + DATA : in std_logic_vector(LPM_WIDTH-1 downto 0); + WRADDRESS : in std_logic_vector(LPM_WIDTHAD-1 downto 0); + WREN : in std_logic; + WRCLOCK : in std_logic := '0'; + WRCLKEN : in std_logic := '1'; + Q : out std_logic_vector(LPM_WIDTH-1 downto 0)); + END COMPONENT; + + -- For Altera + component LPM_RAM_DQ + generic ( + LPM_WIDTH : natural; -- MUST be greater than 0 + LPM_WIDTHAD : natural; -- MUST be greater than 0 + LPM_NUMWORDS : natural := 0; + LPM_INDATA : string := "REGISTERED"; + LPM_ADDRESS_CONTROL: string := "REGISTERED"; + LPM_OUTDATA : string := "REGISTERED"; + LPM_FILE : string := "UNUSED"; + LPM_TYPE : string := "LPM_RAM_DQ"; + USE_EAB : string := "OFF"; + INTENDED_DEVICE_FAMILY : string := "UNUSED"; + LPM_HINT : string := "UNUSED"); + port ( + DATA : in std_logic_vector(LPM_WIDTH-1 downto 0); + ADDRESS : in std_logic_vector(LPM_WIDTHAD-1 downto 0); + INCLOCK : in std_logic := '0'; + OUTCLOCK : in std_logic := '0'; + WE : in std_logic; + Q : out std_logic_vector(LPM_WIDTH-1 downto 0)); + end component; + + -- For Xilinx + component RAM16X1D + -- synthesis translate_off + generic (INIT : bit_vector := X"16"); + -- synthesis translate_on + port (DPO : out STD_ULOGIC; + SPO : out STD_ULOGIC; + A0 : in STD_ULOGIC; + A1 : in STD_ULOGIC; + A2 : in STD_ULOGIC; + A3 : in STD_ULOGIC; + D : in STD_ULOGIC; + DPRA0 : in STD_ULOGIC; + DPRA1 : in STD_ULOGIC; + DPRA2 : in STD_ULOGIC; + DPRA3 : in STD_ULOGIC; + WCLK : in STD_ULOGIC; + WE : in STD_ULOGIC); + end component; + + -- For Xilinx Virtex-5 + component RAM32X1D + -- synthesis translate_off + generic (INIT : bit_vector := X"32"); + -- synthesis translate_on + port (DPO : out STD_ULOGIC; + SPO : out STD_ULOGIC; + A0 : in STD_ULOGIC; + A1 : in STD_ULOGIC; + A2 : in STD_ULOGIC; + A3 : in STD_ULOGIC; + A4 : in STD_ULOGIC; + D : in STD_ULOGIC; + DPRA0 : in STD_ULOGIC; + DPRA1 : in STD_ULOGIC; + DPRA2 : in STD_ULOGIC; + DPRA3 : in STD_ULOGIC; + DPRA4 : in STD_ULOGIC; + WCLK : in STD_ULOGIC; + WE : in STD_ULOGIC); + end component; + + component pc_next + port(clk : in std_logic; + reset_in : in std_logic; + pc_new : in std_logic_vector(31 downto 2); + take_branch : in std_logic; + pause_in : in std_logic; + opcode25_0 : in std_logic_vector(25 downto 0); + pc_source : in pc_source_type; + pc_future : out std_logic_vector(31 downto 2); + pc_current : out std_logic_vector(31 downto 2); + pc_plus4 : out std_logic_vector(31 downto 2)); + end component; + + component mem_ctrl + port(clk : in std_logic; + reset_in : in std_logic; + pause_in : in std_logic; + nullify_op : in std_logic; + address_pc : in std_logic_vector(31 downto 2); + opcode_out : out std_logic_vector(31 downto 0); + + address_in : in std_logic_vector(31 downto 0); + mem_source : in mem_source_type; + data_write : in std_logic_vector(31 downto 0); + data_read : out std_logic_vector(31 downto 0); + pause_out : out std_logic; + + address_next : out std_logic_vector(31 downto 2); + byte_we_next : out std_logic_vector(3 downto 0); + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_w : out std_logic_vector(31 downto 0); + data_r : in std_logic_vector(31 downto 0)); + end component; + + component control + port(opcode : in std_logic_vector(31 downto 0); + intr_signal : in std_logic; + rs_index : out std_logic_vector(5 downto 0); + rt_index : out std_logic_vector(5 downto 0); + rd_index : out std_logic_vector(5 downto 0); + imm_out : out std_logic_vector(15 downto 0); + alu_func : out alu_function_type; + shift_func : out shift_function_type; + mult_func : out mult_function_type; + branch_func : out branch_function_type; + a_source_out : out a_source_type; + b_source_out : out b_source_type; + c_source_out : out c_source_type; + pc_source_out: out pc_source_type; + mem_source_out:out mem_source_type; + exception_out: out std_logic); + end component; + + component reg_bank + generic(memory_type : string := "XILINX_16X"); + port(clk : in std_logic; + reset_in : in std_logic; + pause : in std_logic; + rs_index : in std_logic_vector(5 downto 0); + rt_index : in std_logic_vector(5 downto 0); + rd_index : in std_logic_vector(5 downto 0); + reg_source_out : out std_logic_vector(31 downto 0); + reg_target_out : out std_logic_vector(31 downto 0); + reg_dest_new : in std_logic_vector(31 downto 0); + intr_enable : out std_logic); + end component; + + component bus_mux + port(imm_in : in std_logic_vector(15 downto 0); + reg_source : in std_logic_vector(31 downto 0); + a_mux : in a_source_type; + a_out : out std_logic_vector(31 downto 0); + + reg_target : in std_logic_vector(31 downto 0); + b_mux : in b_source_type; + b_out : out std_logic_vector(31 downto 0); + + c_bus : in std_logic_vector(31 downto 0); + c_memory : in std_logic_vector(31 downto 0); + c_pc : in std_logic_vector(31 downto 2); + c_pc_plus4 : in std_logic_vector(31 downto 2); + c_mux : in c_source_type; + reg_dest_out : out std_logic_vector(31 downto 0); + + branch_func : in branch_function_type; + take_branch : out std_logic); + end component; + + component alu + generic(alu_type : string := "DEFAULT"); + port(a_in : in std_logic_vector(31 downto 0); + b_in : in std_logic_vector(31 downto 0); + alu_function : in alu_function_type; + c_alu : out std_logic_vector(31 downto 0)); + end component; + + component shifter + generic(shifter_type : string := "DEFAULT" ); + port(value : in std_logic_vector(31 downto 0); + shift_amount : in std_logic_vector(4 downto 0); + shift_func : in shift_function_type; + c_shift : out std_logic_vector(31 downto 0)); + end component; + + component mult + generic(mult_type : string := "DEFAULT"); + port(clk : in std_logic; + reset_in : in std_logic; + a, b : in std_logic_vector(31 downto 0); + mult_func : in mult_function_type; + c_mult : out std_logic_vector(31 downto 0); + pause_out : out std_logic); + end component; + + component pipeline + port(clk : in std_logic; + reset : in std_logic; + a_bus : in std_logic_vector(31 downto 0); + a_busD : out std_logic_vector(31 downto 0); + b_bus : in std_logic_vector(31 downto 0); + b_busD : out std_logic_vector(31 downto 0); + alu_func : in alu_function_type; + alu_funcD : out alu_function_type; + shift_func : in shift_function_type; + shift_funcD : out shift_function_type; + mult_func : in mult_function_type; + mult_funcD : out mult_function_type; + reg_dest : in std_logic_vector(31 downto 0); + reg_destD : out std_logic_vector(31 downto 0); + rd_index : in std_logic_vector(5 downto 0); + rd_indexD : out std_logic_vector(5 downto 0); + + rs_index : in std_logic_vector(5 downto 0); + rt_index : in std_logic_vector(5 downto 0); + pc_source : in pc_source_type; + mem_source : in mem_source_type; + a_source : in a_source_type; + b_source : in b_source_type; + c_source : in c_source_type; + c_bus : in std_logic_vector(31 downto 0); + pause_any : in std_logic; + pause_pipeline : out std_logic); + end component; + + component mlite_cpu + generic(memory_type : string := "XILINX_16X"; --ALTERA_LPM, or DUAL_PORT_ + mult_type : string := "DEFAULT"; + shifter_type : string := "DEFAULT"; + alu_type : string := "DEFAULT"; + pipeline_stages : natural := 2); --2 or 3 + port(clk : in std_logic; + reset_in : in std_logic; + intr_in : in std_logic; + + address_next : out std_logic_vector(31 downto 2); --for synch ram + byte_we_next : out std_logic_vector(3 downto 0); + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_w : out std_logic_vector(31 downto 0); + data_r : in std_logic_vector(31 downto 0); + mem_pause : in std_logic); + end component; + + component cache + generic(memory_type : string := "DEFAULT"); + port(clk : in std_logic; + reset : in std_logic; + address_next : in std_logic_vector(31 downto 2); + byte_we_next : in std_logic_vector(3 downto 0); + cpu_address : in std_logic_vector(31 downto 2); + mem_busy : in std_logic; + + cache_access : out std_logic; --access 4KB cache + cache_checking : out std_logic; --checking if cache hit + cache_miss : out std_logic); --cache miss + end component; --cache + + component ram + generic(memory_type : string := "DEFAULT"); + port(clk : in std_logic; + enable : in std_logic; + write_byte_enable : in std_logic_vector(3 downto 0); + address : in std_logic_vector(31 downto 2); + data_write : in std_logic_vector(31 downto 0); + data_read : out std_logic_vector(31 downto 0)); + end component; --ram + + component uart + generic(log_file : string := "UNUSED"); + port(clk : in std_logic; + reset : in std_logic; + enable_read : in std_logic; + enable_write : in std_logic; + data_in : in std_logic_vector(7 downto 0); + data_out : out std_logic_vector(7 downto 0); + uart_read : in std_logic; + uart_write : out std_logic; + busy_write : out std_logic; + data_avail : out std_logic); + end component; --uart + + component eth_dma + port(clk : in std_logic; --25 MHz + reset : in std_logic; + enable_eth : in std_logic; + select_eth : in std_logic; + rec_isr : out std_logic; + send_isr : out std_logic; + + address : out std_logic_vector(31 downto 2); --to DDR + byte_we : out std_logic_vector(3 downto 0); + data_write : out std_logic_vector(31 downto 0); + data_read : in std_logic_vector(31 downto 0); + pause_in : in std_logic; + + mem_address : in std_logic_vector(31 downto 2); --from CPU + mem_byte_we : in std_logic_vector(3 downto 0); + data_w : in std_logic_vector(31 downto 0); + pause_out : out std_logic; + + E_RX_CLK : in std_logic; --2.5 MHz receive + E_RX_DV : in std_logic; --data valid + E_RXD : in std_logic_vector(3 downto 0); --receive nibble + E_TX_CLK : in std_logic; --2.5 MHz transmit + E_TX_EN : out std_logic; --transmit enable + E_TXD : out std_logic_vector(3 downto 0)); --transmit nibble + end component; --eth_dma + + component plasma + generic(memory_type : string := "XILINX_X16"; --"DUAL_PORT_" "ALTERA_LPM"; + log_file : string := "UNUSED"; + ethernet : std_logic := '0'; + use_cache : std_logic := '0'); + port(clk : in std_logic; + reset : in std_logic; + uart_write : out std_logic; + uart_read : in std_logic; + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_write : out std_logic_vector(31 downto 0); + data_read : in std_logic_vector(31 downto 0); + mem_pause_in : in std_logic; + no_ddr_start : out std_logic; + no_ddr_stop : out std_logic; + + gpio0_out : out std_logic_vector(31 downto 0); + gpioA_in : in std_logic_vector(31 downto 0)); + end component; --plasma + + component ddr_ctrl + port(clk : in std_logic; + clk_2x : in std_logic; + reset_in : in std_logic; + + address : in std_logic_vector(25 downto 2); + byte_we : in std_logic_vector(3 downto 0); + data_w : in std_logic_vector(31 downto 0); + data_r : out std_logic_vector(31 downto 0); + active : in std_logic; + no_start : in std_logic; + no_stop : in std_logic; + pause : out std_logic; + + SD_CK_P : out std_logic; --clock_positive + SD_CK_N : out std_logic; --clock_negative + SD_CKE : out std_logic; --clock_enable + + SD_BA : out std_logic_vector(1 downto 0); --bank_address + SD_A : out std_logic_vector(12 downto 0); --address(row or col) + SD_CS : out std_logic; --chip_select + SD_RAS : out std_logic; --row_address_strobe + SD_CAS : out std_logic; --column_address_strobe + SD_WE : out std_logic; --write_enable + + SD_DQ : inout std_logic_vector(15 downto 0); --data + SD_UDM : out std_logic; --upper_byte_enable + SD_UDQS : inout std_logic; --upper_data_strobe + SD_LDM : out std_logic; --low_byte_enable + SD_LDQS : inout std_logic); --low_data_strobe + end component; --ddr + +end; --package mlite_pack + + +package body mlite_pack is + +function bv_adder(a : in std_logic_vector; + b : in std_logic_vector; + do_add: in std_logic) return std_logic_vector is + variable carry_in : std_logic; + variable bb : std_logic_vector(a'length-1 downto 0); + variable result : std_logic_vector(a'length downto 0); +begin + if do_add = '1' then + bb := b; + carry_in := '0'; + else + bb := not b; + carry_in := '1'; + end if; + for index in 0 to a'length-1 loop + result(index) := a(index) xor bb(index) xor carry_in; + carry_in := (carry_in and (a(index) or bb(index))) or + (a(index) and bb(index)); + end loop; + result(a'length) := carry_in xnor do_add; + return result; +end; --function + + +function bv_negate(a : in std_logic_vector) return std_logic_vector is + variable carry_in : std_logic; + variable not_a : std_logic_vector(a'length-1 downto 0); + variable result : std_logic_vector(a'length-1 downto 0); +begin + not_a := not a; + carry_in := '1'; + for index in a'reverse_range loop + result(index) := not_a(index) xor carry_in; + carry_in := carry_in and not_a(index); + end loop; + return result; +end; --function + + +function bv_increment(a : in std_logic_vector(31 downto 2) + ) return std_logic_vector is + variable carry_in : std_logic; + variable result : std_logic_vector(31 downto 2); +begin + carry_in := '1'; + for index in 2 to 31 loop + result(index) := a(index) xor carry_in; + carry_in := a(index) and carry_in; + end loop; + return result; +end; --function + + +function bv_inc(a : in std_logic_vector + ) return std_logic_vector is + variable carry_in : std_logic; + variable result : std_logic_vector(a'length-1 downto 0); +begin + carry_in := '1'; + for index in 0 to a'length-1 loop + result(index) := a(index) xor carry_in; + carry_in := a(index) and carry_in; + end loop; + return result; +end; --function + +end; --package body + + diff --git a/vhdl/mult.vhd b/vhdl/mult.vhd new file mode 100644 index 0000000..643814e --- /dev/null +++ b/vhdl/mult.vhd @@ -0,0 +1,207 @@ +--------------------------------------------------------------------- +-- TITLE: Multiplication and Division Unit +-- AUTHORS: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 1/31/01 +-- FILENAME: mult.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements the multiplication and division unit in 32 clocks. +-- +-- To reduce space, compile your code using the flag "-mno-mul" which +-- will use software base routines in math.c if USE_SW_MULT is defined. +-- Then remove references to the entity mult in mlite_cpu.vhd. +-- +-- MULTIPLICATION +-- long64 answer = 0; +-- for(i = 0; i < 32; ++i) +-- { +-- answer = (answer >> 1) + (((b&1)?a:0) << 31); +-- b = b >> 1; +-- } +-- +-- DIVISION +-- long upper=a, lower=0; +-- a = b << 31; +-- for(i = 0; i < 32; ++i) +-- { +-- lower = lower << 1; +-- if(upper >= a && a && b < 2) +-- { +-- upper = upper - a; +-- lower |= 1; +-- } +-- a = ((b&2) << 30) | (a >> 1); +-- b = b >> 1; +-- } +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use IEEE.std_logic_arith.all; +use work.mlite_pack.all; + +entity mult is + generic(mult_type : string := "DEFAULT"); + port(clk : in std_logic; + reset_in : in std_logic; + a, b : in std_logic_vector(31 downto 0); + mult_func : in mult_function_type; + c_mult : out std_logic_vector(31 downto 0); + pause_out : out std_logic); +end; --entity mult + +architecture logic of mult is + + constant MODE_MULT : std_logic := '1'; + constant MODE_DIV : std_logic := '0'; + + signal mode_reg : std_logic; + signal negate_reg : std_logic; + signal sign_reg : std_logic; + signal sign2_reg : std_logic; + signal count_reg : std_logic_vector(5 downto 0); + signal aa_reg : std_logic_vector(31 downto 0); + signal bb_reg : std_logic_vector(31 downto 0); + signal upper_reg : std_logic_vector(31 downto 0); + signal lower_reg : std_logic_vector(31 downto 0); + + signal a_neg : std_logic_vector(31 downto 0); + signal b_neg : std_logic_vector(31 downto 0); + signal sum : std_logic_vector(32 downto 0); + +begin + + -- Result + c_mult <= lower_reg when mult_func = MULT_READ_LO and negate_reg = '0' else + bv_negate(lower_reg) when mult_func = MULT_READ_LO + and negate_reg = '1' else + upper_reg when mult_func = MULT_READ_HI else + ZERO; + pause_out <= '1' when (count_reg /= "000000") and + (mult_func = MULT_READ_LO or mult_func = MULT_READ_HI) else '0'; + + -- ABS and remainder signals + a_neg <= bv_negate(a); + b_neg <= bv_negate(b); + sum <= bv_adder(upper_reg, aa_reg, mode_reg); + + --multiplication/division unit + mult_proc: process(clk, reset_in, a, b, mult_func, + a_neg, b_neg, sum, sign_reg, mode_reg, negate_reg, + count_reg, aa_reg, bb_reg, upper_reg, lower_reg) + variable count : std_logic_vector(2 downto 0); + begin + count := "001"; + if reset_in = '1' then + mode_reg <= '0'; + negate_reg <= '0'; + sign_reg <= '0'; + sign2_reg <= '0'; + count_reg <= "000000"; + aa_reg <= ZERO; + bb_reg <= ZERO; + upper_reg <= ZERO; + lower_reg <= ZERO; + elsif rising_edge(clk) then + case mult_func is + when MULT_WRITE_LO => + lower_reg <= a; + negate_reg <= '0'; + when MULT_WRITE_HI => + upper_reg <= a; + negate_reg <= '0'; + when MULT_MULT => + mode_reg <= MODE_MULT; + aa_reg <= a; + bb_reg <= b; + upper_reg <= ZERO; + count_reg <= "100000"; + negate_reg <= '0'; + sign_reg <= '0'; + sign2_reg <= '0'; + when MULT_SIGNED_MULT => + mode_reg <= MODE_MULT; + if b(31) = '0' then + aa_reg <= a; + bb_reg <= b; + else + aa_reg <= a_neg; + bb_reg <= b_neg; + end if; + sign_reg <= a(31) xor b(31); + sign2_reg <= '0'; + upper_reg <= ZERO; + count_reg <= "100000"; + negate_reg <= '0'; + when MULT_DIVIDE => + mode_reg <= MODE_DIV; + aa_reg <= b(0) & ZERO(30 downto 0); + bb_reg <= b; + upper_reg <= a; + count_reg <= "100000"; + negate_reg <= '0'; + when MULT_SIGNED_DIVIDE => + mode_reg <= MODE_DIV; + if b(31) = '0' then + aa_reg(31) <= b(0); + bb_reg <= b; + else + aa_reg(31) <= b_neg(0); + bb_reg <= b_neg; + end if; + if a(31) = '0' then + upper_reg <= a; + else + upper_reg <= a_neg; + end if; + aa_reg(30 downto 0) <= ZERO(30 downto 0); + count_reg <= "100000"; + negate_reg <= a(31) xor b(31); + when others => + + if count_reg /= "000000" then + if mode_reg = MODE_MULT then + -- Multiplication + if bb_reg(0) = '1' then + upper_reg <= (sign_reg xor sum(32)) & sum(31 downto 1); + lower_reg <= sum(0) & lower_reg(31 downto 1); + sign2_reg <= sign2_reg or sign_reg; + sign_reg <= '0'; + bb_reg <= '0' & bb_reg(31 downto 1); + -- The following six lines are optional for speedup + --elsif bb_reg(3 downto 0) = "0000" and sign2_reg = '0' and + -- count_reg(5 downto 2) /= "0000" then + -- upper_reg <= "0000" & upper_reg(31 downto 4); + -- lower_reg <= upper_reg(3 downto 0) & lower_reg(31 downto 4); + -- count := "100"; + -- bb_reg <= "0000" & bb_reg(31 downto 4); + else + upper_reg <= sign2_reg & upper_reg(31 downto 1); + lower_reg <= upper_reg(0) & lower_reg(31 downto 1); + bb_reg <= '0' & bb_reg(31 downto 1); + end if; + else + -- Division + if sum(32) = '0' and aa_reg /= ZERO and + bb_reg(31 downto 1) = ZERO(31 downto 1) then + upper_reg <= sum(31 downto 0); + lower_reg(0) <= '1'; + else + lower_reg(0) <= '0'; + end if; + aa_reg <= bb_reg(1) & aa_reg(31 downto 1); + lower_reg(31 downto 1) <= lower_reg(30 downto 0); + bb_reg <= '0' & bb_reg(31 downto 1); + end if; + count_reg <= count_reg - count; + end if; --count + + end case; + + end if; + + end process; + +end; --architecture logic diff --git a/vhdl/pc_next.vhd b/vhdl/pc_next.vhd new file mode 100644 index 0000000..3c0d9b0 --- /dev/null +++ b/vhdl/pc_next.vhd @@ -0,0 +1,71 @@ +--------------------------------------------------------------------- +-- TITLE: Program Counter Next +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/8/01 +-- FILENAME: pc_next.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements the Program Counter logic. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; + +entity pc_next is + port(clk : in std_logic; + reset_in : in std_logic; + pc_new : in std_logic_vector(31 downto 2); + take_branch : in std_logic; + pause_in : in std_logic; + opcode25_0 : in std_logic_vector(25 downto 0); + pc_source : in pc_source_type; + pc_future : out std_logic_vector(31 downto 2); + pc_current : out std_logic_vector(31 downto 2); + pc_plus4 : out std_logic_vector(31 downto 2)); +end; --pc_next + +architecture logic of pc_next is + signal pc_reg : std_logic_vector(31 downto 2); +begin + +pc_select: process(clk, reset_in, pc_new, take_branch, pause_in, + opcode25_0, pc_source, pc_reg) + variable pc_inc : std_logic_vector(31 downto 2); + variable pc_next : std_logic_vector(31 downto 2); +begin + pc_inc := bv_increment(pc_reg); --pc_reg+1 + + case pc_source is + when FROM_INC4 => + pc_next := pc_inc; + when FROM_OPCODE25_0 => + pc_next := pc_reg(31 downto 28) & opcode25_0; + when FROM_BRANCH | FROM_LBRANCH => + if take_branch = '1' then + pc_next := pc_new; + else + pc_next := pc_inc; + end if; + when others => + pc_next := pc_inc; + end case; + + if pause_in = '1' then + pc_next := pc_reg; + end if; + + if reset_in = '1' then + pc_reg <= ZERO(31 downto 2); + pc_next := pc_reg; + elsif rising_edge(clk) then + pc_reg <= pc_next; + end if; + + pc_future <= pc_next; + pc_current <= pc_reg; + pc_plus4 <= pc_inc; +end process; + +end; --logic diff --git a/vhdl/pipeline.vhd b/vhdl/pipeline.vhd new file mode 100644 index 0000000..09dfcee --- /dev/null +++ b/vhdl/pipeline.vhd @@ -0,0 +1,139 @@ +--------------------------------------------------------------------- +-- TITLE: Pipeline +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 6/24/02 +-- FILENAME: pipeline.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Controls the three stage pipeline by delaying the signals: +-- a_bus, b_bus, alu/shift/mult_func, c_source, and rs_index. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; + +--Note: sigD <= sig after rising_edge(clk) +entity pipeline is + port(clk : in std_logic; + reset : in std_logic; + a_bus : in std_logic_vector(31 downto 0); + a_busD : out std_logic_vector(31 downto 0); + b_bus : in std_logic_vector(31 downto 0); + b_busD : out std_logic_vector(31 downto 0); + alu_func : in alu_function_type; + alu_funcD : out alu_function_type; + shift_func : in shift_function_type; + shift_funcD : out shift_function_type; + mult_func : in mult_function_type; + mult_funcD : out mult_function_type; + reg_dest : in std_logic_vector(31 downto 0); + reg_destD : out std_logic_vector(31 downto 0); + rd_index : in std_logic_vector(5 downto 0); + rd_indexD : out std_logic_vector(5 downto 0); + + rs_index : in std_logic_vector(5 downto 0); + rt_index : in std_logic_vector(5 downto 0); + pc_source : in pc_source_type; + mem_source : in mem_source_type; + a_source : in a_source_type; + b_source : in b_source_type; + c_source : in c_source_type; + c_bus : in std_logic_vector(31 downto 0); + pause_any : in std_logic; + pause_pipeline : out std_logic); +end; --entity pipeline + +architecture logic of pipeline is + signal rd_index_reg : std_logic_vector(5 downto 0); + signal reg_dest_reg : std_logic_vector(31 downto 0); + signal reg_dest_delay : std_logic_vector(31 downto 0); + signal c_source_reg : c_source_type; + signal pause_enable_reg : std_logic; +begin + +--When operating in three stage pipeline mode, the following signals +--are delayed by one clock cycle: a_bus, b_bus, alu/shift/mult_func, +--c_source, and rd_index. +pipeline3: process(clk, reset, a_bus, b_bus, alu_func, shift_func, mult_func, + rd_index, rd_index_reg, pause_any, pause_enable_reg, + rs_index, rt_index, + pc_source, mem_source, a_source, b_source, c_source, c_source_reg, + reg_dest, reg_dest_reg, reg_dest_delay, c_bus) + variable pause_mult_clock : std_logic; + variable freeze_pipeline : std_logic; +begin + if (pc_source /= FROM_INC4 and pc_source /= FROM_OPCODE25_0) or + mem_source /= MEM_FETCH or + (mult_func = MULT_READ_LO or mult_func = MULT_READ_HI) then + pause_mult_clock := '1'; + else + pause_mult_clock := '0'; + end if; + + freeze_pipeline := not (pause_mult_clock and pause_enable_reg) and pause_any; + pause_pipeline <= pause_mult_clock and pause_enable_reg; + rd_indexD <= rd_index_reg; + + -- The value written back into the register bank, signal reg_dest is tricky. + -- If reg_dest comes from the ALU via the signal c_bus, it is already delayed + -- into stage #3, because a_busD and b_busD are delayed. If reg_dest comes from + -- c_memory, pc_current, or pc_plus4 then reg_dest hasn't yet been delayed into + -- stage #3. + -- Instead of delaying c_memory, pc_current, and pc_plus4, these signals + -- are multiplexed into reg_dest which is then delayed. The decision to use + -- the already delayed c_bus or the delayed value of reg_dest (reg_dest_reg) is + -- based on a delayed value of c_source (c_source_reg). + + if c_source_reg = C_FROM_ALU then + reg_dest_delay <= c_bus; --delayed by 1 clock cycle via a_busD & b_busD + else + reg_dest_delay <= reg_dest_reg; --need to delay 1 clock cycle from reg_dest + end if; + reg_destD <= reg_dest_delay; + + if reset = '1' then + a_busD <= ZERO; + b_busD <= ZERO; + alu_funcD <= ALU_NOTHING; + shift_funcD <= SHIFT_NOTHING; + mult_funcD <= MULT_NOTHING; + reg_dest_reg <= ZERO; + c_source_reg <= "000"; + rd_index_reg <= "000000"; + pause_enable_reg <= '0'; + elsif rising_edge(clk) then + if freeze_pipeline = '0' then + if (rs_index = "000000" or rs_index /= rd_index_reg) or + (a_source /= A_FROM_REG_SOURCE or pause_enable_reg = '0') then + a_busD <= a_bus; + else + a_busD <= reg_dest_delay; --rs from previous operation (bypass stage) + end if; + + if (rt_index = "000000" or rt_index /= rd_index_reg) or + (b_source /= B_FROM_REG_TARGET or pause_enable_reg = '0') then + b_busD <= b_bus; + else + b_busD <= reg_dest_delay; --rt from previous operation + end if; + + alu_funcD <= alu_func; + shift_funcD <= shift_func; + mult_funcD <= mult_func; + reg_dest_reg <= reg_dest; + c_source_reg <= c_source; + rd_index_reg <= rd_index; + end if; + + if pause_enable_reg = '0' and pause_any = '0' then + pause_enable_reg <= '1'; --enable pause_pipeline + elsif pause_mult_clock = '1' then + pause_enable_reg <= '0'; --disable pause_pipeline + end if; + end if; + +end process; --pipeline3 + +end; --logic diff --git a/vhdl/plasma.vhd b/vhdl/plasma.vhd new file mode 100644 index 0000000..130576b --- /dev/null +++ b/vhdl/plasma.vhd @@ -0,0 +1,320 @@ +--------------------------------------------------------------------- +-- TITLE: Plasma (CPU core with memory) +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 6/4/02 +-- FILENAME: plasma.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- This entity combines the CPU core with memory and a UART. +-- +-- Memory Map: +-- 0x00000000 - 0x0000ffff Internal RAM (8KB) +-- 0x10000000 - 0x100fffff External RAM (1MB) +-- Access all Misc registers with 32-bit accesses +-- 0x20000000 Uart Write (will pause CPU if busy) +-- 0x20000000 Uart Read +-- 0x20000010 IRQ Mask +-- 0x20000020 IRQ Status +-- 0x20000030 GPIO0 Out Set bits +-- 0x20000040 GPIO0 Out Clear bits +-- 0x20000050 GPIOA In +-- 0x20000060 Counter +-- 0x20000070 Ethernet transmit count +-- IRQ bits: +-- 7 GPIO31 +-- 6 ^GPIO31 +-- 5 EthernetSendDone +-- 4 EthernetReceive +-- 3 Counter(18) +-- 2 ^Counter(18) +-- 1 ^UartWriteBusy +-- 0 UartDataAvailable +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; + +entity plasma is + generic(memory_type : string := "XILINX_16X"; --"DUAL_PORT_" "ALTERA_LPM"; + log_file : string := "UNUSED"; + ethernet : std_logic := '0'; + use_cache : std_logic := '0'); + port(clk : in std_logic; + reset : in std_logic; + + uart_write : out std_logic; + uart_read : in std_logic; + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_write : out std_logic_vector(31 downto 0); + data_read : in std_logic_vector(31 downto 0); + mem_pause_in : in std_logic; + no_ddr_start : out std_logic; + no_ddr_stop : out std_logic; + + gpio0_out : out std_logic_vector(31 downto 0); + gpioA_in : in std_logic_vector(31 downto 0)); +end; --entity plasma + +architecture logic of plasma is + signal address_next : std_logic_vector(31 downto 2); + signal byte_we_next : std_logic_vector(3 downto 0); + signal cpu_address : std_logic_vector(31 downto 0); + signal cpu_byte_we : std_logic_vector(3 downto 0); + signal cpu_data_w : std_logic_vector(31 downto 0); + signal cpu_data_r : std_logic_vector(31 downto 0); + signal cpu_pause : std_logic; + + signal data_read_uart : std_logic_vector(7 downto 0); + signal write_enable : std_logic; + signal eth_pause_in : std_logic; + signal eth_pause : std_logic; + signal mem_busy : std_logic; + + signal enable_misc : std_logic; + signal enable_uart : std_logic; + signal enable_uart_read : std_logic; + signal enable_uart_write : std_logic; + signal enable_eth : std_logic; + + signal gpio0_reg : std_logic_vector(31 downto 0); + signal uart_write_busy : std_logic; + signal uart_data_avail : std_logic; + signal irq_mask_reg : std_logic_vector(7 downto 0); + signal irq_status : std_logic_vector(7 downto 0); + signal irq : std_logic; + signal irq_eth_rec : std_logic; + signal irq_eth_send : std_logic; + signal counter_reg : std_logic_vector(31 downto 0); + + signal ram_enable : std_logic; + signal ram_byte_we : std_logic_vector(3 downto 0); + signal ram_address : std_logic_vector(31 downto 2); + signal ram_data_w : std_logic_vector(31 downto 0); + signal ram_data_r : std_logic_vector(31 downto 0); + + signal cache_access : std_logic; + signal cache_checking : std_logic; + signal cache_miss : std_logic; + signal cache_hit : std_logic; + +begin --architecture + write_enable <= '1' when cpu_byte_we /= "0000" else '0'; + mem_busy <= eth_pause or mem_pause_in; + cache_hit <= cache_checking and not cache_miss; + cpu_pause <= (uart_write_busy and enable_uart and write_enable) or --UART busy + cache_miss or --Cache wait + (cpu_address(28) and not cache_hit and mem_busy); --DDR or flash + irq_status <= gpioA_in(31) & not gpioA_in(31) & + irq_eth_send & irq_eth_rec & + counter_reg(18) & not counter_reg(18) & + not uart_write_busy & uart_data_avail; + irq <= '1' when (irq_status and irq_mask_reg) /= ZERO(7 downto 0) else '0'; + gpio0_out(31 downto 29) <= gpio0_reg(31 downto 29); + gpio0_out(23 downto 0) <= gpio0_reg(23 downto 0); + + enable_misc <= '1' when cpu_address(30 downto 28) = "010" else '0'; + enable_uart <= '1' when enable_misc = '1' and cpu_address(7 downto 4) = "0000" else '0'; + enable_uart_read <= enable_uart and not write_enable; + enable_uart_write <= enable_uart and write_enable; + enable_eth <= '1' when enable_misc = '1' and cpu_address(7 downto 4) = "0111" else '0'; + cpu_address(1 downto 0) <= "00"; + + u1_cpu: mlite_cpu + generic map (memory_type => memory_type) + PORT MAP ( + clk => clk, + reset_in => reset, + intr_in => irq, + + address_next => address_next, --before rising_edge(clk) + byte_we_next => byte_we_next, + + address => cpu_address(31 downto 2), --after rising_edge(clk) + byte_we => cpu_byte_we, + data_w => cpu_data_w, + data_r => cpu_data_r, + mem_pause => cpu_pause); + + opt_cache: if use_cache = '0' generate + cache_access <= '0'; + cache_checking <= '0'; + cache_miss <= '0'; + end generate; + + opt_cache2: if use_cache = '1' generate + --Control 4KB unified cache that uses the upper 4KB of the 8KB + --internal RAM. Only lowest 2MB of DDR is cached. + u_cache: cache + generic map (memory_type => memory_type) + PORT MAP ( + clk => clk, + reset => reset, + address_next => address_next, + byte_we_next => byte_we_next, + cpu_address => cpu_address(31 downto 2), + mem_busy => mem_busy, + + cache_access => cache_access, --access 4KB cache + cache_checking => cache_checking, --checking if cache hit + cache_miss => cache_miss); --cache miss + end generate; --opt_cache2 + + no_ddr_start <= not eth_pause and cache_checking; + no_ddr_stop <= not eth_pause and cache_miss; + eth_pause_in <= mem_pause_in or (not eth_pause and cache_miss and not cache_checking); + + misc_proc: process(clk, reset, cpu_address, enable_misc, + ram_data_r, data_read, data_read_uart, cpu_pause, + irq_mask_reg, irq_status, gpio0_reg, write_enable, + cache_checking, + gpioA_in, counter_reg, cpu_data_w) + begin + case cpu_address(30 downto 28) is + when "000" => --internal RAM + cpu_data_r <= ram_data_r; + when "001" => --external RAM + if cache_checking = '1' then + cpu_data_r <= ram_data_r; --cache + else + cpu_data_r <= data_read; --DDR + end if; + when "010" => --misc + case cpu_address(6 downto 4) is + when "000" => --uart + cpu_data_r <= ZERO(31 downto 8) & data_read_uart; + when "001" => --irq_mask + cpu_data_r <= ZERO(31 downto 8) & irq_mask_reg; + when "010" => --irq_status + cpu_data_r <= ZERO(31 downto 8) & irq_status; + when "011" => --gpio0 + cpu_data_r <= gpio0_reg; + when "101" => --gpioA + cpu_data_r <= gpioA_in; + when "110" => --counter + cpu_data_r <= counter_reg; + when others => + cpu_data_r <= gpioA_in; + end case; + when "011" => --flash + cpu_data_r <= data_read; + when others => + cpu_data_r <= ZERO; + end case; + + if reset = '1' then + irq_mask_reg <= ZERO(7 downto 0); + gpio0_reg <= ZERO; + counter_reg <= ZERO; + elsif rising_edge(clk) then + if cpu_pause = '0' then + if enable_misc = '1' and write_enable = '1' then + if cpu_address(6 downto 4) = "001" then + irq_mask_reg <= cpu_data_w(7 downto 0); + elsif cpu_address(6 downto 4) = "011" then + gpio0_reg <= gpio0_reg or cpu_data_w; + elsif cpu_address(6 downto 4) = "100" then + gpio0_reg <= gpio0_reg and not cpu_data_w; + end if; + end if; + end if; + counter_reg <= bv_inc(counter_reg); + end if; + end process; + + ram_proc: process(cache_access, cache_miss, + address_next, cpu_address, + byte_we_next, cpu_data_w, data_read) + begin + if cache_access = '1' then --Check if cache hit or write through + ram_enable <= '1'; + ram_byte_we <= byte_we_next; + ram_address(31 downto 2) <= ZERO(31 downto 16) & + "0001" & address_next(11 downto 2); + ram_data_w <= cpu_data_w; + elsif cache_miss = '1' then --Update cache after cache miss + ram_enable <= '1'; + ram_byte_we <= "1111"; + ram_address(31 downto 2) <= ZERO(31 downto 16) & + "0001" & cpu_address(11 downto 2); + ram_data_w <= data_read; + else --Normal non-cache access + if address_next(30 downto 28) = "000" then + ram_enable <= '1'; + else + ram_enable <= '0'; + end if; + ram_byte_we <= byte_we_next; + ram_address(31 downto 2) <= address_next(31 downto 2); + ram_data_w <= cpu_data_w; + end if; + end process; + + u2_ram: ram + generic map (memory_type => memory_type) + port map ( + clk => clk, + enable => ram_enable, + write_byte_enable => ram_byte_we, + address => ram_address, + data_write => ram_data_w, + data_read => ram_data_r); + + u3_uart: uart + generic map (log_file => log_file) + port map( + clk => clk, + reset => reset, + enable_read => enable_uart_read, + enable_write => enable_uart_write, + data_in => cpu_data_w(7 downto 0), + data_out => data_read_uart, + uart_read => uart_read, + uart_write => uart_write, + busy_write => uart_write_busy, + data_avail => uart_data_avail); + + dma_gen: if ethernet = '0' generate + address <= cpu_address(31 downto 2); + byte_we <= cpu_byte_we; + data_write <= cpu_data_w; + eth_pause <= '0'; + gpio0_out(28 downto 24) <= ZERO(28 downto 24); + irq_eth_rec <= '0'; + irq_eth_send <= '0'; + end generate; + + dma_gen2: if ethernet = '1' generate + u4_eth: eth_dma + port map( + clk => clk, + reset => reset, + enable_eth => gpio0_reg(24), + select_eth => enable_eth, + rec_isr => irq_eth_rec, + send_isr => irq_eth_send, + + address => address, --to DDR + byte_we => byte_we, + data_write => data_write, + data_read => data_read, + pause_in => eth_pause_in, + + mem_address => cpu_address(31 downto 2), --from CPU + mem_byte_we => cpu_byte_we, + data_w => cpu_data_w, + pause_out => eth_pause, + + E_RX_CLK => gpioA_in(20), + E_RX_DV => gpioA_in(19), + E_RXD => gpioA_in(18 downto 15), + E_TX_CLK => gpioA_in(14), + E_TX_EN => gpio0_out(28), + E_TXD => gpio0_out(27 downto 24)); + end generate; + +end; --architecture logic + diff --git a/vhdl/plasma_3e.vhd b/vhdl/plasma_3e.vhd new file mode 100644 index 0000000..8879fda --- /dev/null +++ b/vhdl/plasma_3e.vhd @@ -0,0 +1,289 @@ +--------------------------------------------------------------------- +-- TITLE: Plamsa Interface (clock divider and interface to FPGA board) +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 9/15/07 +-- FILENAME: plasma_3e.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- This entity divides the clock by two and interfaces to the +-- Xilinx Spartan-3E XC3S200FT256-4 FPGA with DDR. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; +--use work.mlite_pack.all; + +entity plasma_3e is + port(CLK_50MHZ : in std_logic; + RS232_DCE_RXD : in std_logic; + RS232_DCE_TXD : out std_logic; + + SD_CK_P : out std_logic; --DDR SDRAM clock_positive + SD_CK_N : out std_logic; --clock_negative + SD_CKE : out std_logic; --clock_enable + + SD_BA : out std_logic_vector(1 downto 0); --bank_address + SD_A : out std_logic_vector(12 downto 0); --address(row or col) + SD_CS : out std_logic; --chip_select + SD_RAS : out std_logic; --row_address_strobe + SD_CAS : out std_logic; --column_address_strobe + SD_WE : out std_logic; --write_enable + + SD_DQ : inout std_logic_vector(15 downto 0); --data + SD_UDM : out std_logic; --upper_byte_enable + SD_UDQS : inout std_logic; --upper_data_strobe + SD_LDM : out std_logic; --low_byte_enable + SD_LDQS : inout std_logic; --low_data_strobe + + E_MDC : out std_logic; --Ethernet PHY + E_MDIO : inout std_logic; --management data in/out + E_RX_CLK : in std_logic; --receive clock + E_RX_DV : in std_logic; --data valid + E_RXD : in std_logic_vector(3 downto 0); + E_TX_CLK : in std_logic; --transmit clock + E_TX_EN : out std_logic; --data valid + E_TXD : out std_logic_vector(3 downto 0); + + SF_CE0 : out std_logic; --NOR flash + SF_OE : out std_logic; + SF_WE : out std_logic; + SF_BYTE : out std_logic; + SF_STS : in std_logic; --status + SF_A : out std_logic_vector(24 downto 0); + SF_D : inout std_logic_vector(15 downto 1); + SPI_MISO : inout std_logic; + + VGA_VSYNC : out std_logic; --VGA port + VGA_HSYNC : out std_logic; + VGA_RED : out std_logic; + VGA_GREEN : out std_logic; + VGA_BLUE : out std_logic; + + PS2_CLK : in std_logic; --Keyboard + PS2_DATA : in std_logic; + + LED : out std_logic_vector(7 downto 0); + ROT_CENTER : in std_logic; + ROT_A : in std_logic; + ROT_B : in std_logic; + BTN_EAST : in std_logic; + BTN_NORTH : in std_logic; + BTN_SOUTH : in std_logic; + BTN_WEST : in std_logic; + SW : in std_logic_vector(3 downto 0)); +end; --entity plasma_if + + +architecture logic of plasma_3e is + + component plasma + generic(memory_type : string := "XILINX_16X"; --"DUAL_PORT_" "ALTERA_LPM"; + log_file : string := "UNUSED"; + ethernet : std_logic := '0'; + use_cache : std_logic := '0'); + port(clk : in std_logic; + reset : in std_logic; + uart_write : out std_logic; + uart_read : in std_logic; + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_write : out std_logic_vector(31 downto 0); + data_read : in std_logic_vector(31 downto 0); + mem_pause_in : in std_logic; + no_ddr_start : out std_logic; + no_ddr_stop : out std_logic; + + gpio0_out : out std_logic_vector(31 downto 0); + gpioA_in : in std_logic_vector(31 downto 0)); + end component; --plasma + + component ddr_ctrl + port(clk : in std_logic; + clk_2x : in std_logic; + reset_in : in std_logic; + + address : in std_logic_vector(25 downto 2); + byte_we : in std_logic_vector(3 downto 0); + data_w : in std_logic_vector(31 downto 0); + data_r : out std_logic_vector(31 downto 0); + active : in std_logic; + no_start : in std_logic; + no_stop : in std_logic; + pause : out std_logic; + + SD_CK_P : out std_logic; --clock_positive + SD_CK_N : out std_logic; --clock_negative + SD_CKE : out std_logic; --clock_enable + + SD_BA : out std_logic_vector(1 downto 0); --bank_address + SD_A : out std_logic_vector(12 downto 0); --address(row or col) + SD_CS : out std_logic; --chip_select + SD_RAS : out std_logic; --row_address_strobe + SD_CAS : out std_logic; --column_address_strobe + SD_WE : out std_logic; --write_enable + + SD_DQ : inout std_logic_vector(15 downto 0); --data + SD_UDM : out std_logic; --upper_byte_enable + SD_UDQS : inout std_logic; --upper_data_strobe + SD_LDM : out std_logic; --low_byte_enable + SD_LDQS : inout std_logic); --low_data_strobe + end component; --ddr + + signal clk_reg : std_logic; + signal address : std_logic_vector(31 downto 2); + signal data_write : std_logic_vector(31 downto 0); + signal data_read : std_logic_vector(31 downto 0); + signal data_r_ddr : std_logic_vector(31 downto 0); + signal byte_we : std_logic_vector(3 downto 0); + signal write_enable : std_logic; + signal pause_ddr : std_logic; + signal pause : std_logic; + signal no_ddr_start : std_logic; + signal no_ddr_stop : std_logic; + signal ddr_active : std_logic; + signal flash_active : std_logic; + signal flash_cnt : std_logic_vector(1 downto 0); + signal flash_we : std_logic; + signal reset : std_logic; + signal gpio0_out : std_logic_vector(31 downto 0); + signal gpio0_in : std_logic_vector(31 downto 0); + +begin --architecture + --Divide 50 MHz clock by two + clk_div: process(reset, CLK_50MHZ, clk_reg) + begin + if reset = '1' then + clk_reg <= '0'; + elsif rising_edge(CLK_50MHZ) then + clk_reg <= not clk_reg; + end if; + end process; --clk_div + + reset <= ROT_CENTER; + E_TX_EN <= gpio0_out(28); --Ethernet + E_TXD <= gpio0_out(27 downto 24); + E_MDC <= gpio0_out(23); + E_MDIO <= gpio0_out(21) when gpio0_out(22) = '1' else 'Z'; + VGA_VSYNC <= gpio0_out(20); + VGA_HSYNC <= gpio0_out(19); + VGA_RED <= gpio0_out(18); + VGA_GREEN <= gpio0_out(17); + VGA_BLUE <= gpio0_out(16); + LED <= gpio0_out(7 downto 0); + gpio0_in(31 downto 21) <= (others => '0'); + gpio0_in(20 downto 13) <= E_RX_CLK & E_RX_DV & E_RXD & E_TX_CLK & E_MDIO; + gpio0_in(12 downto 10) <= SF_STS & PS2_CLK & PS2_DATA; + gpio0_in(9 downto 0) <= ROT_A & ROT_B & BTN_EAST & BTN_NORTH & + BTN_SOUTH & BTN_WEST & SW; + ddr_active <= '1' when address(31 downto 28) = "0001" else '0'; + flash_active <= '1' when address(31 downto 28) = "0011" else '0'; + write_enable <= '1' when byte_we /= "0000" else '0'; + + u1_plama: plasma + generic map (memory_type => "XILINX_16X", + log_file => "UNUSED", + ethernet => '1', + use_cache => '1') + --generic map (memory_type => "DUAL_PORT_", + -- log_file => "output2.txt", + -- ethernet => '1') + PORT MAP ( + clk => clk_reg, + reset => reset, + uart_write => RS232_DCE_TXD, + uart_read => RS232_DCE_RXD, + + address => address, + byte_we => byte_we, + data_write => data_write, + data_read => data_read, + mem_pause_in => pause, + no_ddr_start => no_ddr_start, + no_ddr_stop => no_ddr_stop, + + gpio0_out => gpio0_out, + gpioA_in => gpio0_in); + + u2_ddr: ddr_ctrl + port map ( + clk => clk_reg, + clk_2x => CLK_50MHZ, + reset_in => reset, + + address => address(25 downto 2), + byte_we => byte_we, + data_w => data_write, + data_r => data_r_ddr, + active => ddr_active, + no_start => no_ddr_start, + no_stop => no_ddr_stop, + pause => pause_ddr, + + SD_CK_P => SD_CK_P, --clock_positive + SD_CK_N => SD_CK_N, --clock_negative + SD_CKE => SD_CKE, --clock_enable + + SD_BA => SD_BA, --bank_address + SD_A => SD_A, --address(row or col) + SD_CS => SD_CS, --chip_select + SD_RAS => SD_RAS, --row_address_strobe + SD_CAS => SD_CAS, --column_address_strobe + SD_WE => SD_WE, --write_enable + + SD_DQ => SD_DQ, --data + SD_UDM => SD_UDM, --upper_byte_enable + SD_UDQS => SD_UDQS, --upper_data_strobe + SD_LDM => SD_LDM, --low_byte_enable + SD_LDQS => SD_LDQS); --low_data_strobe + + --Flash control (only lower 16-bit data lines connected) + flash_ctrl: process(reset, clk_reg, flash_active, write_enable, + flash_cnt, pause_ddr) + begin + if reset = '1' then + flash_cnt <= "00"; + flash_we <= '1'; + elsif rising_edge(clk_reg) then + if flash_active = '0' then + flash_cnt <= "00"; + flash_we <= '1'; + else + if write_enable = '1' and flash_cnt(1) = '0' then + flash_we <= '0'; + else + flash_we <= '1'; + end if; + if flash_cnt /= "11" then + flash_cnt <= flash_cnt + 1; + end if; + end if; + end if; --rising_edge(clk_reg) + if pause_ddr = '1' or (flash_active = '1' and flash_cnt /= "11") then + pause <= '1'; + else + pause <= '0'; + end if; + end process; --flash_ctrl + + SF_CE0 <= not flash_active; + SF_OE <= write_enable or not flash_active; + SF_WE <= flash_we; + SF_BYTE <= '1'; --16-bit access + SF_A <= address(25 downto 2) & '0' when flash_active = '1' else + "0000000000000000000000000"; + SF_D <= data_write(15 downto 1) when + flash_active = '1' and write_enable = '1' + else "ZZZZZZZZZZZZZZZ"; + SPI_MISO <= data_write(0) when + flash_active = '1' and write_enable = '1' + else 'Z'; + data_read(31 downto 16) <= data_r_ddr(31 downto 16); + data_read(15 downto 0) <= data_r_ddr(15 downto 0) when flash_active = '0' + else SF_D & SPI_MISO; + +end; --architecture logic + diff --git a/vhdl/plasma_S3E.npl b/vhdl/plasma_S3E.npl new file mode 100644 index 0000000..579c2b3 --- /dev/null +++ b/vhdl/plasma_S3E.npl @@ -0,0 +1,38 @@ +JDF G +// Created by Project Navigator ver 1.0 +PROJECT jop +DESIGN jop +DEVFAM spartan3e +DEVFAMTIME 0 +DEVICE xc3s500e +DEVICETIME 0 +DEVPKG fg320 +DEVPKGTIME 0 +DEVSPEED -4 +DEVTOPLEVELMODULETYPE HDL +TOPLEVELMODULETYPETIME 0 +DEVSYNTHESISTOOL XST (VHDL/Verilog) +SYNTHESISTOOLTIME 0 +DEVSIMULATOR Modelsim +SIMULATORTIME 0 +DEVGENERATEDSIMULATIONMODEL VHDL +GENERATEDSIMULATIONMODELTIME 0 +SOURCE mlite_pack.vhd +SOURCE plasma_3e.vhd +SOURCE ddr_ctrl.vhd +SOURCE plasma.vhd +SOURCE ram_image.vhd +SOURCE uart.vhd +SOURCE eth_dma.vhd +SOURCE mlite_cpu.vhd +SOURCE alu.vhd +SOURCE bus_mux.vhd +SOURCE control.vhd +SOURCE mem_ctrl.vhd +SOURCE mult.vhd +SOURCE pipeline.vhd +SOURCE pc_next.vhd +SOURCE reg_bank.vhd +SOURCE shifter.vhd +SOURCE cache.vhd +DEPASSOC spartan3e spartan3e.ucf diff --git a/vhdl/plasma_if.ucf b/vhdl/plasma_if.ucf new file mode 100644 index 0000000..51b354f --- /dev/null +++ b/vhdl/plasma_if.ucf @@ -0,0 +1,111 @@ +NET "clk_in" TNM_NET = "clk_in"; +TIMESPEC "TS_clk_in" = PERIOD "clk_in" 20 ns HIGH 50 %; +#NET "clk_reg1" TNM_NET = "clk_reg1"; +#TIMESPEC "TS_clk_reg1" = PERIOD "clk_reg1" 40 ns HIGH 50 %; +NET "clk_reg1" TNM_NET = "clk_reg1"; +TIMESPEC "TS_clk_reg1" = PERIOD "clk_reg1" 39.9 ns HIGH 50 %; +#PACE: Start of Constraints generated by PACE +#PACE: Start of PACE I/O Pin Assignments +NET "clk_in" LOC = "T9"; +NET "gpio0_out<0>" LOC = "K12"; +NET "gpio0_out<10>" LOC = "N15"; +NET "gpio0_out<11>" LOC = "P15"; +NET "gpio0_out<12>" LOC = "R16"; +NET "gpio0_out<13>" LOC = "F13"; +NET "gpio0_out<14>" LOC = "N16"; +NET "gpio0_out<15>" LOC = "P16"; +NET "gpio0_out<16>" LOC = "E13"; +NET "gpio0_out<17>" LOC = "F14"; +NET "gpio0_out<18>" LOC = "G14"; +NET "gpio0_out<19>" LOC = "D14"; +NET "gpio0_out<1>" LOC = "P14"; +NET "gpio0_out<24>" LOC = "R12"; +NET "gpio0_out<25>" LOC = "T12"; +NET "gpio0_out<26>" LOC = "R11"; +NET "gpio0_out<27>" LOC = "R9"; +NET "gpio0_out<28>" LOC = "T10"; +NET "gpio0_out<2>" LOC = "L12"; +NET "gpio0_out<3>" LOC = "N14"; +NET "gpio0_out<4>" LOC = "P13"; +NET "gpio0_out<5>" LOC = "N12"; +NET "gpio0_out<6>" LOC = "P12"; +NET "gpio0_out<7>" LOC = "P11"; +NET "gpio0_out<8>" LOC = "E14"; +NET "gpio0_out<9>" LOC = "G13"; +NET "gpioA_in<0>" LOC = "F12"; +NET "gpioA_in<10>" LOC = "L13"; +NET "gpioA_in<1>" LOC = "G12"; +NET "gpioA_in<2>" LOC = "H14"; +NET "gpioA_in<30>" LOC = "M15"; +NET "gpioA_in<31>" LOC = "M16"; +NET "gpioA_in<3>" LOC = "H13"; +NET "gpioA_in<4>" LOC = "J14"; +NET "gpioA_in<5>" LOC = "J13"; +NET "gpioA_in<6>" LOC = "K14"; +NET "gpioA_in<7>" LOC = "K13"; +NET "gpioA_in<8>" LOC = "M13"; +NET "gpioA_in<9>" LOC = "M14"; +NET "ram_address<10>" LOC = "E3"; +NET "ram_address<11>" LOC = "E4"; +NET "ram_address<12>" LOC = "G5"; +NET "ram_address<13>" LOC = "H3"; +NET "ram_address<14>" LOC = "H4"; +NET "ram_address<15>" LOC = "J4"; +NET "ram_address<16>" LOC = "J3"; +NET "ram_address<17>" LOC = "K3"; +NET "ram_address<18>" LOC = "K5"; +NET "ram_address<19>" LOC = "L3"; +NET "ram_address<2>" LOC = "L5"; +NET "ram_address<3>" LOC = "N3"; +NET "ram_address<4>" LOC = "M4"; +NET "ram_address<5>" LOC = "M3"; +NET "ram_address<6>" LOC = "L4"; +NET "ram_address<7>" LOC = "G4"; +NET "ram_address<8>" LOC = "F3"; +NET "ram_address<9>" LOC = "F4"; +NET "ram_ce1_n" LOC = "P7"; +NET "ram_ce2_n" LOC = "N5"; +NET "ram_data<0>" LOC = "P2"; +NET "ram_data<10>" LOC = "G1"; +NET "ram_data<11>" LOC = "F5"; +NET "ram_data<12>" LOC = "C3"; +NET "ram_data<13>" LOC = "K2"; +NET "ram_data<14>" LOC = "M1"; +NET "ram_data<15>" LOC = "N1"; +NET "ram_data<16>" LOC = "N7"; +NET "ram_data<17>" LOC = "T8"; +NET "ram_data<18>" LOC = "R6"; +NET "ram_data<19>" LOC = "T5"; +NET "ram_data<1>" LOC = "N2"; +NET "ram_data<20>" LOC = "R5"; +NET "ram_data<21>" LOC = "C2"; +NET "ram_data<22>" LOC = "C1"; +NET "ram_data<23>" LOC = "B1"; +NET "ram_data<24>" LOC = "D3"; +NET "ram_data<25>" LOC = "P8"; +NET "ram_data<26>" LOC = "F2"; +NET "ram_data<27>" LOC = "H1"; +NET "ram_data<28>" LOC = "J2"; +NET "ram_data<29>" LOC = "L2"; +NET "ram_data<2>" LOC = "M2"; +NET "ram_data<30>" LOC = "P1"; +NET "ram_data<31>" LOC = "R1"; +NET "ram_data<3>" LOC = "K1"; +NET "ram_data<4>" LOC = "J1"; +NET "ram_data<5>" LOC = "G2"; +NET "ram_data<6>" LOC = "E1"; +NET "ram_data<7>" LOC = "D1"; +NET "ram_data<8>" LOC = "D2"; +NET "ram_data<9>" LOC = "E2"; +NET "ram_lb1_n" LOC = "P6"; +NET "ram_lb2_n" LOC = "P5"; +NET "ram_oe_n" LOC = "K4"; +NET "ram_ub1_n" LOC = "T4"; +NET "ram_ub2_n" LOC = "R4"; +NET "ram_we_n" LOC = "G3"; +NET "reset" LOC = "L14"; +NET "uart_read" LOC = "T13"; +NET "uart_write" LOC = "R13"; +#PACE: Start of PACE Area Constraints +#PACE: Start of PACE Prohibit Constraints +#PACE: End of Constraints generated by PACE diff --git a/vhdl/plasma_if.vhd b/vhdl/plasma_if.vhd new file mode 100644 index 0000000..e36530e --- /dev/null +++ b/vhdl/plasma_if.vhd @@ -0,0 +1,152 @@ +--------------------------------------------------------------------- +-- TITLE: Plamsa Interface (clock divider and interface to FPGA board) +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 6/6/02 +-- FILENAME: plasma_if.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- This entity divides the clock by two and interfaces to the +-- Altera EP20K200EFC484-2X FPGA board. +-- Xilinx Spartan-3 XC3S200FT256-4 FPGA. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +--use work.mlite_pack.all; + +entity plasma_if is + port(clk_in : in std_logic; + reset : in std_logic; + uart_read : in std_logic; + uart_write : out std_logic; + + ram_address : out std_logic_vector(31 downto 2); + ram_data : inout std_logic_vector(31 downto 0); + ram_ce1_n : out std_logic; + ram_ub1_n : out std_logic; + ram_lb1_n : out std_logic; + ram_ce2_n : out std_logic; + ram_ub2_n : out std_logic; + ram_lb2_n : out std_logic; + ram_we_n : out std_logic; + ram_oe_n : out std_logic; + + gpio0_out : out std_logic_vector(31 downto 0); + gpioA_in : in std_logic_vector(31 downto 0)); +end; --entity plasma_if + + +architecture logic of plasma_if is + + component plasma + generic(memory_type : string := "XILINX_16X"; --"DUAL_PORT_" "ALTERA_LPM"; + log_file : string := "UNUSED"); + port(clk : in std_logic; + reset : in std_logic; + uart_write : out std_logic; + uart_read : in std_logic; + + address : out std_logic_vector(31 downto 2); + byte_we : out std_logic_vector(3 downto 0); + data_write : out std_logic_vector(31 downto 0); + data_read : in std_logic_vector(31 downto 0); + mem_pause_in : in std_logic; + + gpio0_out : out std_logic_vector(31 downto 0); + gpioA_in : in std_logic_vector(31 downto 0)); + end component; --plasma + + signal clk_reg : std_logic; + signal we_n_next : std_logic; + signal we_n_reg : std_logic; + signal mem_address : std_logic_vector(31 downto 2); + signal data_write : std_logic_vector(31 downto 0); + signal data_reg : std_logic_vector(31 downto 0); + signal byte_we : std_logic_vector(3 downto 0); + signal mem_pause_in : std_logic; + +begin --architecture + --Divide 50 MHz clock by two + clk_div: process(reset, clk_in, clk_reg, we_n_next) + begin + if reset = '1' then + clk_reg <= '0'; + elsif rising_edge(clk_in) then + clk_reg <= not clk_reg; + end if; + + if reset = '1' then + we_n_reg <= '1'; + data_reg <= (others => '0'); + elsif falling_edge(clk_in) then + we_n_reg <= we_n_next or not clk_reg; + data_reg <= ram_data; + end if; + end process; --clk_div + + mem_pause_in <= '0'; + ram_address <= mem_address(31 downto 2); + ram_we_n <= we_n_reg; + + --For Xilinx Spartan-3 Starter Kit + ram_control: + process(clk_reg, mem_address, byte_we, data_write) + begin + if mem_address(30 downto 28) = "001" then --RAM + ram_ce1_n <= '0'; + ram_ce2_n <= '0'; + if byte_we = "0000" then --read + ram_data <= (others => 'Z'); + ram_ub1_n <= '0'; + ram_lb1_n <= '0'; + ram_ub2_n <= '0'; + ram_lb2_n <= '0'; + we_n_next <= '1'; + ram_oe_n <= '0'; + else --write + if clk_reg = '1' then + ram_data <= (others => 'Z'); + else + ram_data <= data_write; + end if; + ram_ub1_n <= not byte_we(3); + ram_lb1_n <= not byte_we(2); + ram_ub2_n <= not byte_we(1); + ram_lb2_n <= not byte_we(0); + we_n_next <= '0'; + ram_oe_n <= '1'; + end if; + else + ram_data <= (others => 'Z'); + ram_ce1_n <= '1'; + ram_ub1_n <= '1'; + ram_lb1_n <= '1'; + ram_ce2_n <= '1'; + ram_ub2_n <= '1'; + ram_lb2_n <= '1'; + we_n_next <= '1'; + ram_oe_n <= '1'; + end if; + end process; --ram_control + + u1_plama: plasma + generic map (memory_type => "XILINX_16X", + log_file => "UNUSED") + PORT MAP ( + clk => clk_reg, + reset => reset, + uart_write => uart_write, + uart_read => uart_read, + + address => mem_address, + byte_we => byte_we, + data_write => data_write, + data_read => data_reg, + mem_pause_in => mem_pause_in, + + gpio0_out => gpio0_out, + gpioA_in => gpioA_in); + +end; --architecture logic + diff --git a/vhdl/ram.vhd b/vhdl/ram.vhd new file mode 100644 index 0000000..9c0f511 --- /dev/null +++ b/vhdl/ram.vhd @@ -0,0 +1,176 @@ +--------------------------------------------------------------------- +-- TITLE: Random Access Memory +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 4/21/01 +-- FILENAME: ram.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements the RAM, reads the executable from either "code.txt", +-- or for Altera "code[0-3].hex". +-- Modified from "The Designer's Guide to VHDL" by Peter J. Ashenden +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_misc.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_textio.all; +use std.textio.all; +use work.mlite_pack.all; + +entity ram is + generic(memory_type : string := "DEFAULT"); + port(clk : in std_logic; + enable : in std_logic; + write_byte_enable : in std_logic_vector(3 downto 0); + address : in std_logic_vector(31 downto 2); + data_write : in std_logic_vector(31 downto 0); + data_read : out std_logic_vector(31 downto 0)); +end; --entity ram + +architecture logic of ram is + constant ADDRESS_WIDTH : natural := 13; +begin + + generic_ram: + if memory_type /= "ALTERA_LPM" generate + begin + --Simulate a synchronous RAM + ram_proc: process(clk, enable, write_byte_enable, + address, data_write) --mem_write, mem_sel + variable mem_size : natural := 2 ** ADDRESS_WIDTH; + variable data : std_logic_vector(31 downto 0); + subtype word is std_logic_vector(data_write'length-1 downto 0); + type storage_array is + array(natural range 0 to mem_size/4 - 1) of word; + variable storage : storage_array; + variable index : natural := 0; + file load_file : text open read_mode is "code.txt"; + variable hex_file_line : line; + begin + + --Load in the ram executable image + if index = 0 then + while not endfile(load_file) loop +--The following two lines had to be commented out for synthesis + readline(load_file, hex_file_line); + hread(hex_file_line, data); + storage(index) := data; + index := index + 1; + end loop; + end if; + + if rising_edge(clk) then + index := conv_integer(address(ADDRESS_WIDTH-1 downto 2)); + data := storage(index); + + if enable = '1' then + if write_byte_enable(0) = '1' then + data(7 downto 0) := data_write(7 downto 0); + end if; + if write_byte_enable(1) = '1' then + data(15 downto 8) := data_write(15 downto 8); + end if; + if write_byte_enable(2) = '1' then + data(23 downto 16) := data_write(23 downto 16); + end if; + if write_byte_enable(3) = '1' then + data(31 downto 24) := data_write(31 downto 24); + end if; + end if; + + if write_byte_enable /= "0000" then + storage(index) := data; + end if; + end if; + + data_read <= data; + end process; + end generate; --generic_ram + + + altera_ram: + if memory_type = "ALTERA_LPM" generate + signal byte_we : std_logic_vector(3 downto 0); + begin + byte_we <= write_byte_enable when enable = '1' else "0000"; + lpm_ram_io_component0 : lpm_ram_dq + GENERIC MAP ( + intended_device_family => "UNUSED", + lpm_width => 8, + lpm_widthad => ADDRESS_WIDTH-2, + lpm_indata => "REGISTERED", + lpm_address_control => "REGISTERED", + lpm_outdata => "UNREGISTERED", + lpm_file => "code0.hex", + use_eab => "ON", + lpm_type => "LPM_RAM_DQ") + PORT MAP ( + data => data_write(31 downto 24), + address => address(ADDRESS_WIDTH-1 downto 2), + inclock => clk, + we => byte_we(3), + q => data_read(31 downto 24)); + + lpm_ram_io_component1 : lpm_ram_dq + GENERIC MAP ( + intended_device_family => "UNUSED", + lpm_width => 8, + lpm_widthad => ADDRESS_WIDTH-2, + lpm_indata => "REGISTERED", + lpm_address_control => "REGISTERED", + lpm_outdata => "UNREGISTERED", + lpm_file => "code1.hex", + use_eab => "ON", + lpm_type => "LPM_RAM_DQ") + PORT MAP ( + data => data_write(23 downto 16), + address => address(ADDRESS_WIDTH-1 downto 2), + inclock => clk, + we => byte_we(2), + q => data_read(23 downto 16)); + + lpm_ram_io_component2 : lpm_ram_dq + GENERIC MAP ( + intended_device_family => "UNUSED", + lpm_width => 8, + lpm_widthad => ADDRESS_WIDTH-2, + lpm_indata => "REGISTERED", + lpm_address_control => "REGISTERED", + lpm_outdata => "UNREGISTERED", + lpm_file => "code2.hex", + use_eab => "ON", + lpm_type => "LPM_RAM_DQ") + PORT MAP ( + data => data_write(15 downto 8), + address => address(ADDRESS_WIDTH-1 downto 2), + inclock => clk, + we => byte_we(1), + q => data_read(15 downto 8)); + + lpm_ram_io_component3 : lpm_ram_dq + GENERIC MAP ( + intended_device_family => "UNUSED", + lpm_width => 8, + lpm_widthad => ADDRESS_WIDTH-2, + lpm_indata => "REGISTERED", + lpm_address_control => "REGISTERED", + lpm_outdata => "UNREGISTERED", + lpm_file => "code3.hex", + use_eab => "ON", + lpm_type => "LPM_RAM_DQ") + PORT MAP ( + data => data_write(7 downto 0), + address => address(ADDRESS_WIDTH-1 downto 2), + inclock => clk, + we => byte_we(0), + q => data_read(7 downto 0)); + + end generate; --altera_ram + + + --For XILINX see ram_xilinx.vhd + +end; --architecture logic diff --git a/vhdl/ram_xilinx.vhd b/vhdl/ram_xilinx.vhd new file mode 100644 index 0000000..a1f2a03 --- /dev/null +++ b/vhdl/ram_xilinx.vhd @@ -0,0 +1,2641 @@ +--------------------------------------------------------------------- +-- TITLE: Random Access Memory for Xilinx +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 11/06/05 +-- FILENAME: ram_xilinx.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements Plasma internal RAM as RAMB for Spartan 3x +-- +-- Compile the MIPS C and assembly code into "test.axf". +-- Run convert.exe to change "test.axf" to "code.txt" which +-- will contain the hex values of the opcodes. +-- Next run "ram_image ram_xilinx.vhd code.txt ram_image.vhd", +-- to create the "ram_image.vhd" file that will have the opcodes +-- correctly placed inside the INIT_00 => strings. +-- Then include ram_image.vhd in the simulation/synthesis. +-- +-- Warning: Addresses 0x1000 - 0x1FFF are reserved for the cache +-- if the DDR cache is enabled. +--------------------------------------------------------------------- +-- UPDATED: 09/07/10 Olivier Rinaudo (orinaudo@gmail.com) +-- new behaviour: 8KB expandable to 64KB of internal RAM +-- +-- MEMORY MAP +-- 0000..1FFF : 8KB 8KB block0 (upper 4KB used as DDR cache) +-- 2000..3FFF : 8KB 16KB block1 +-- 4000..5FFF : 8KB 24KB block2 +-- 6000..7FFF : 8KB 32KB block3 +-- 8000..9FFF : 8KB 40KB block4 +-- A000..BFFF : 8KB 48KB block5 +-- C000..DFFF : 8KB 56KB block6 +-- E000..FFFF : 8KB 64KB block7 +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use work.mlite_pack.all; + +library UNISIM; +use UNISIM.vcomponents.all; + +entity ram is + generic(memory_type : string := "DEFAULT"; + --Number of 8KB blocks of internal RAM, up to 64KB (1 to 8) + block_count : integer := 1); + port(clk : in std_logic; + enable : in std_logic; + write_byte_enable : in std_logic_vector(3 downto 0); + address : in std_logic_vector(31 downto 2); + data_write : in std_logic_vector(31 downto 0); + data_read : out std_logic_vector(31 downto 0)); +end; --entity ram + +architecture logic of ram is + --type + type mem32_vector IS ARRAY (NATURAL RANGE<>) OF std_logic_vector(31 downto 0); + + --Which 8KB block + alias block_sel: std_logic_vector(2 downto 0) is address(15 downto 13); + + --Address within a 8KB block (without lower two bits) + alias block_addr : std_logic_vector(10 downto 0) is address(12 downto 2); + + --Block enable with 1 bit per memory block + signal block_enable: std_logic_vector(7 downto 0); + + --Block Data Out + signal block_do: mem32_vector(7 downto 0); + + --Remember which block was selected + signal block_sel_buf: std_logic_vector(2 downto 0); + +begin + block_enable<= "00000001" when (enable='1') and (block_sel="000") else + "00000010" when (enable='1') and (block_sel="001") else + "00000100" when (enable='1') and (block_sel="010") else + "00001000" when (enable='1') and (block_sel="011") else + "00010000" when (enable='1') and (block_sel="100") else + "00100000" when (enable='1') and (block_sel="101") else + "01000000" when (enable='1') and (block_sel="110") else + "10000000" when (enable='1') and (block_sel="111") else + "00000000"; + + proc_blocksel: process (clk, block_sel) is + begin + if rising_edge(clk) then + block_sel_buf <= block_sel; + end if; + end process; + + proc_do: process (block_do, block_sel_buf) is + begin + data_read <= block_do(conv_integer(block_sel_buf)); + end process; + + -- BLOCKS generation + block0: if (block_count > 0) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"000000000000000000000000000000000000000000000000000000000c080400", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(0)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(0), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"000000000000000000000000000000000000000000000000000000000d090501", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(0)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(0), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"000000000000000000000000000000000000000000000000000000000e0a0602", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(0)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(0), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"000000000000000000000000000000000000000000000000000000000f0b0703", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(0)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(0), + SSR => ZERO(0), + WE => write_byte_enable(0)); + end generate; --block0 + + + block1: if (block_count > 1) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(1)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(1), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(1)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(1), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(1)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(1), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(1)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(1), + SSR => ZERO(0), + WE => write_byte_enable(0)); + + end generate; --block1 + + + block2: if (block_count > 2) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(2)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(2), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(2)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(2), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(2)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(2), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(2)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(2), + SSR => ZERO(0), + WE => write_byte_enable(0)); + + end generate; --block2 + + + block3: if (block_count > 3) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(3)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(3), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(3)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(3), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(3)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(3), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(3)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(3), + SSR => ZERO(0), + WE => write_byte_enable(0)); + + end generate; --block3 + + + block4: if (block_count > 4) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(4)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(4), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(4)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(4), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(4)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(4), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(4)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(4), + SSR => ZERO(0), + WE => write_byte_enable(0)); + + end generate; --block4 + + + block5: if (block_count > 5) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(5)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(5), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(5)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(5), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(5)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(5), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(5)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(5), + SSR => ZERO(0), + WE => write_byte_enable(0)); + + end generate; --block5 + + + block6: if (block_count > 6) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(6)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(6), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(6)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(6), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(6)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(6), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(6)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(6), + SSR => ZERO(0), + WE => write_byte_enable(0)); + + end generate; --block6 + + + block7: if (block_count > 7) generate + begin + + ram_byte3 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(7)(31 downto 24), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(31 downto 24), + DIP => ZERO(0 downto 0), + EN => block_enable(7), + SSR => ZERO(0), + WE => write_byte_enable(3)); + + ram_byte2 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(7)(23 downto 16), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(23 downto 16), + DIP => ZERO(0 downto 0), + EN => block_enable(7), + SSR => ZERO(0), + WE => write_byte_enable(2)); + + ram_byte1 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(7)(15 downto 8), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(15 downto 8), + DIP => ZERO(0 downto 0), + EN => block_enable(7), + SSR => ZERO(0), + WE => write_byte_enable(1)); + + ram_byte0 : RAMB16_S9 + generic map ( +INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", +INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000" +) + port map ( + DO => block_do(7)(7 downto 0), + DOP => open, + ADDR => block_addr, + CLK => clk, + DI => data_write(7 downto 0), + DIP => ZERO(0 downto 0), + EN => block_enable(7), + SSR => ZERO(0), + WE => write_byte_enable(0)); + + end generate; --block7 + +end; --architecture logic diff --git a/vhdl/reg_bank.vhd b/vhdl/reg_bank.vhd new file mode 100644 index 0000000..91a2ef5 --- /dev/null +++ b/vhdl/reg_bank.vhd @@ -0,0 +1,375 @@ +--------------------------------------------------------------------- +-- TITLE: Register Bank +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/2/01 +-- FILENAME: reg_bank.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements a register bank with 32 registers that are 32-bits wide. +-- There are two read-ports and one write port. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use work.mlite_pack.all; +--library UNISIM; --May need to uncomment for ModelSim +--use UNISIM.vcomponents.all; --May need to uncomment for ModelSim + +entity reg_bank is + generic(memory_type : string := "XILINX_16X"); + port(clk : in std_logic; + reset_in : in std_logic; + pause : in std_logic; + rs_index : in std_logic_vector(5 downto 0); + rt_index : in std_logic_vector(5 downto 0); + rd_index : in std_logic_vector(5 downto 0); + reg_source_out : out std_logic_vector(31 downto 0); + reg_target_out : out std_logic_vector(31 downto 0); + reg_dest_new : in std_logic_vector(31 downto 0); + intr_enable : out std_logic); +end; --entity reg_bank + + +-------------------------------------------------------------------- +-- The ram_block architecture attempts to use TWO dual-port memories. +-- Different FPGAs and ASICs need different implementations. +-- Choose one of the RAM implementations below. +-- I need feedback on this section! +-------------------------------------------------------------------- +architecture ram_block of reg_bank is + signal intr_enable_reg : std_logic; + type ram_type is array(31 downto 0) of std_logic_vector(31 downto 0); + + --controls access to dual-port memories + signal addr_read1, addr_read2 : std_logic_vector(4 downto 0); + signal addr_write : std_logic_vector(4 downto 0); + signal data_out1, data_out2 : std_logic_vector(31 downto 0); + signal write_enable : std_logic; + +begin + +reg_proc: process(clk, rs_index, rt_index, rd_index, reg_dest_new, + intr_enable_reg, data_out1, data_out2, reset_in, pause) +begin + --setup for first dual-port memory + if rs_index = "101110" then --reg_epc CP0 14 + addr_read1 <= "00000"; + else + addr_read1 <= rs_index(4 downto 0); + end if; + case rs_index is + when "000000" => reg_source_out <= ZERO; + when "101100" => reg_source_out <= ZERO(31 downto 1) & intr_enable_reg; + --interrupt vector address = 0x3c + when "111111" => reg_source_out <= ZERO(31 downto 8) & "00111100"; + when others => reg_source_out <= data_out1; + end case; + + --setup for second dual-port memory + addr_read2 <= rt_index(4 downto 0); + case rt_index is + when "000000" => reg_target_out <= ZERO; + when others => reg_target_out <= data_out2; + end case; + + --setup write port for both dual-port memories + if rd_index /= "000000" and rd_index /= "101100" and pause = '0' then + write_enable <= '1'; + else + write_enable <= '0'; + end if; + if rd_index = "101110" then --reg_epc CP0 14 + addr_write <= "00000"; + else + addr_write <= rd_index(4 downto 0); + end if; + + if reset_in = '1' then + intr_enable_reg <= '0'; + elsif rising_edge(clk) then + if rd_index = "101110" then --reg_epc CP0 14 + intr_enable_reg <= '0'; --disable interrupts + elsif rd_index = "101100" then + intr_enable_reg <= reg_dest_new(0); + end if; + end if; + + intr_enable <= intr_enable_reg; +end process; + + +-------------------------------------------------------------- +---- Pick only ONE of the dual-port RAM implementations below! +-------------------------------------------------------------- + + -- Option #1 + -- One tri-port RAM, two read-ports, one write-port + -- 32 registers 32-bits wide + tri_port_mem: + if memory_type = "TRI_PORT_X" generate + ram_proc: process(clk, addr_read1, addr_read2, + addr_write, reg_dest_new, write_enable) + variable tri_port_ram : ram_type := (others => ZERO); + begin + data_out1 <= tri_port_ram(conv_integer(addr_read1)); + data_out2 <= tri_port_ram(conv_integer(addr_read2)); + if rising_edge(clk) then + if write_enable = '1' then + tri_port_ram(conv_integer(addr_write)) := reg_dest_new; + end if; + end if; + end process; + end generate; --tri_port_mem + + + -- Option #2 + -- Two dual-port RAMs, each with one read-port and one write-port + dual_port_mem: + if memory_type = "DUAL_PORT_" generate + ram_proc2: process(clk, addr_read1, addr_read2, + addr_write, reg_dest_new, write_enable) + variable dual_port_ram1 : ram_type := (others => ZERO); + variable dual_port_ram2 : ram_type := (others => ZERO); + begin + data_out1 <= dual_port_ram1(conv_integer(addr_read1)); + data_out2 <= dual_port_ram2(conv_integer(addr_read2)); + if rising_edge(clk) then + if write_enable = '1' then + dual_port_ram1(conv_integer(addr_write)) := reg_dest_new; + dual_port_ram2(conv_integer(addr_write)) := reg_dest_new; + end if; + end if; + end process; + end generate; --dual_port_mem + + + -- Option #3 + -- RAM16X1D: 16 x 1 positive edge write, asynchronous read dual-port + -- distributed RAM for all Xilinx FPGAs + -- From library UNISIM; use UNISIM.vcomponents.all; + xilinx_16x1d: + if memory_type = "XILINX_16X" generate + signal data_out1A, data_out1B : std_logic_vector(31 downto 0); + signal data_out2A, data_out2B : std_logic_vector(31 downto 0); + signal weA, weB : std_logic; + signal no_connect : std_logic_vector(127 downto 0); + begin + weA <= write_enable and not addr_write(4); --lower 16 registers + weB <= write_enable and addr_write(4); --upper 16 registers + + reg_loop: for i in 0 to 31 generate + begin + --Read port 1 lower 16 registers + reg_bit1a : RAM16X1D + port map ( + WCLK => clk, -- Port A write clock input + WE => weA, -- Port A write enable input + A0 => addr_write(0), -- Port A address[0] input bit + A1 => addr_write(1), -- Port A address[1] input bit + A2 => addr_write(2), -- Port A address[2] input bit + A3 => addr_write(3), -- Port A address[3] input bit + D => reg_dest_new(i), -- Port A 1-bit data input + DPRA0 => addr_read1(0), -- Port B address[0] input bit + DPRA1 => addr_read1(1), -- Port B address[1] input bit + DPRA2 => addr_read1(2), -- Port B address[2] input bit + DPRA3 => addr_read1(3), -- Port B address[3] input bit + DPO => data_out1A(i), -- Port B 1-bit data output + SPO => no_connect(i) -- Port A 1-bit data output + ); + --Read port 1 upper 16 registers + reg_bit1b : RAM16X1D + port map ( + WCLK => clk, -- Port A write clock input + WE => weB, -- Port A write enable input + A0 => addr_write(0), -- Port A address[0] input bit + A1 => addr_write(1), -- Port A address[1] input bit + A2 => addr_write(2), -- Port A address[2] input bit + A3 => addr_write(3), -- Port A address[3] input bit + D => reg_dest_new(i), -- Port A 1-bit data input + DPRA0 => addr_read1(0), -- Port B address[0] input bit + DPRA1 => addr_read1(1), -- Port B address[1] input bit + DPRA2 => addr_read1(2), -- Port B address[2] input bit + DPRA3 => addr_read1(3), -- Port B address[3] input bit + DPO => data_out1B(i), -- Port B 1-bit data output + SPO => no_connect(32+i) -- Port A 1-bit data output + ); + --Read port 2 lower 16 registers + reg_bit2a : RAM16X1D + port map ( + WCLK => clk, -- Port A write clock input + WE => weA, -- Port A write enable input + A0 => addr_write(0), -- Port A address[0] input bit + A1 => addr_write(1), -- Port A address[1] input bit + A2 => addr_write(2), -- Port A address[2] input bit + A3 => addr_write(3), -- Port A address[3] input bit + D => reg_dest_new(i), -- Port A 1-bit data input + DPRA0 => addr_read2(0), -- Port B address[0] input bit + DPRA1 => addr_read2(1), -- Port B address[1] input bit + DPRA2 => addr_read2(2), -- Port B address[2] input bit + DPRA3 => addr_read2(3), -- Port B address[3] input bit + DPO => data_out2A(i), -- Port B 1-bit data output + SPO => no_connect(64+i) -- Port A 1-bit data output + ); + --Read port 2 upper 16 registers + reg_bit2b : RAM16X1D + port map ( + WCLK => clk, -- Port A write clock input + WE => weB, -- Port A write enable input + A0 => addr_write(0), -- Port A address[0] input bit + A1 => addr_write(1), -- Port A address[1] input bit + A2 => addr_write(2), -- Port A address[2] input bit + A3 => addr_write(3), -- Port A address[3] input bit + D => reg_dest_new(i), -- Port A 1-bit data input + DPRA0 => addr_read2(0), -- Port B address[0] input bit + DPRA1 => addr_read2(1), -- Port B address[1] input bit + DPRA2 => addr_read2(2), -- Port B address[2] input bit + DPRA3 => addr_read2(3), -- Port B address[3] input bit + DPO => data_out2B(i), -- Port B 1-bit data output + SPO => no_connect(96+i) -- Port A 1-bit data output + ); + end generate; --reg_loop + + data_out1 <= data_out1A when addr_read1(4)='0' else data_out1B; + data_out2 <= data_out2A when addr_read2(4)='0' else data_out2B; + end generate; --xilinx_16x1d + + + -- Option #4 + -- RAM32X1D: 32 x 1 positive edge write, asynchronous read dual-port + -- distributed RAM for 5-LUT Xilinx FPGAs such as Virtex-5 + -- From library UNISIM; use UNISIM.vcomponents.all; + xilinx_32x1d: + if memory_type = "XILINX_32X" generate + signal no_connect : std_logic_vector(63 downto 0); + begin + reg_loop: for i in 0 to 31 generate + begin + --Read port 1 + reg_bit1 : RAM32X1D + port map ( + WCLK => clk, -- Port A write clock input + WE => write_enable, -- Port A write enable input + A0 => addr_write(0), -- Port A address[0] input bit + A1 => addr_write(1), -- Port A address[1] input bit + A2 => addr_write(2), -- Port A address[2] input bit + A3 => addr_write(3), -- Port A address[3] input bit + A4 => addr_write(4), -- Port A address[4] input bit + D => reg_dest_new(i), -- Port A 1-bit data input + DPRA0 => addr_read1(0), -- Port B address[0] input bit + DPRA1 => addr_read1(1), -- Port B address[1] input bit + DPRA2 => addr_read1(2), -- Port B address[2] input bit + DPRA3 => addr_read1(3), -- Port B address[3] input bit + DPRA4 => addr_read1(4), -- Port B address[4] input bit + DPO => data_out1(i), -- Port B 1-bit data output + SPO => no_connect(i) -- Port A 1-bit data output + ); + --Read port 2 + reg_bit2 : RAM32X1D + port map ( + WCLK => clk, -- Port A write clock input + WE => write_enable, -- Port A write enable input + A0 => addr_write(0), -- Port A address[0] input bit + A1 => addr_write(1), -- Port A address[1] input bit + A2 => addr_write(2), -- Port A address[2] input bit + A3 => addr_write(3), -- Port A address[3] input bit + A4 => addr_write(4), -- Port A address[4] input bit + D => reg_dest_new(i), -- Port A 1-bit data input + DPRA0 => addr_read2(0), -- Port B address[0] input bit + DPRA1 => addr_read2(1), -- Port B address[1] input bit + DPRA2 => addr_read2(2), -- Port B address[2] input bit + DPRA3 => addr_read2(3), -- Port B address[3] input bit + DPRA4 => addr_read2(4), -- Port B address[4] input bit + DPO => data_out2(i), -- Port B 1-bit data output + SPO => no_connect(32+i) -- Port A 1-bit data output + ); + end generate; --reg_loop + end generate; --xilinx_32x1d + + + -- Option #5 + -- Altera LPM_RAM_DP + altera_mem: + if memory_type = "ALTERA_LPM" generate + signal clk_delayed : std_logic; + signal addr_reg : std_logic_vector(4 downto 0); + signal data_reg : std_logic_vector(31 downto 0); + signal q1 : std_logic_vector(31 downto 0); + signal q2 : std_logic_vector(31 downto 0); + begin + -- Altera dual port RAMs must have the addresses registered (sampled + -- at the rising edge). This is very unfortunate. + -- Therefore, the dual port RAM read clock must delayed so that + -- the read address signal can be sent from the mem_ctrl block. + -- This solution also delays the how fast the registers are read so the + -- maximum clock speed is cut in half (12.5 MHz instead of 25 MHz). + + clk_delayed <= not clk; --Could be delayed by 1/4 clock cycle instead + dpram_bypass: process(clk, addr_write, reg_dest_new, write_enable) + begin + if rising_edge(clk) and write_enable = '1' then + addr_reg <= addr_write; + data_reg <= reg_dest_new; + end if; + end process; --dpram_bypass + + -- Bypass dpram if reading what was just written (Altera limitation) + data_out1 <= q1 when addr_read1 /= addr_reg else data_reg; + data_out2 <= q2 when addr_read2 /= addr_reg else data_reg; + + lpm_ram_dp_component1 : lpm_ram_dp + generic map ( + LPM_WIDTH => 32, + LPM_WIDTHAD => 5, + --LPM_NUMWORDS => 0, + LPM_INDATA => "REGISTERED", + LPM_OUTDATA => "UNREGISTERED", + LPM_RDADDRESS_CONTROL => "REGISTERED", + LPM_WRADDRESS_CONTROL => "REGISTERED", + LPM_FILE => "UNUSED", + LPM_TYPE => "LPM_RAM_DP", + USE_EAB => "ON", + INTENDED_DEVICE_FAMILY => "UNUSED", + RDEN_USED => "FALSE", + LPM_HINT => "UNUSED") + port map ( + RDCLOCK => clk_delayed, + RDCLKEN => '1', + RDADDRESS => addr_read1, + RDEN => '1', + DATA => reg_dest_new, + WRADDRESS => addr_write, + WREN => write_enable, + WRCLOCK => clk, + WRCLKEN => '1', + Q => q1); + lpm_ram_dp_component2 : lpm_ram_dp + generic map ( + LPM_WIDTH => 32, + LPM_WIDTHAD => 5, + --LPM_NUMWORDS => 0, + LPM_INDATA => "REGISTERED", + LPM_OUTDATA => "UNREGISTERED", + LPM_RDADDRESS_CONTROL => "REGISTERED", + LPM_WRADDRESS_CONTROL => "REGISTERED", + LPM_FILE => "UNUSED", + LPM_TYPE => "LPM_RAM_DP", + USE_EAB => "ON", + INTENDED_DEVICE_FAMILY => "UNUSED", + RDEN_USED => "FALSE", + LPM_HINT => "UNUSED") + port map ( + RDCLOCK => clk_delayed, + RDCLKEN => '1', + RDADDRESS => addr_read2, + RDEN => '1', + DATA => reg_dest_new, + WRADDRESS => addr_write, + WREN => write_enable, + WRCLOCK => clk, + WRCLKEN => '1', + Q => q2); + end generate; --altera_mem + +end; --architecture ram_block diff --git a/vhdl/shifter.vhd b/vhdl/shifter.vhd new file mode 100644 index 0000000..f4a574b --- /dev/null +++ b/vhdl/shifter.vhd @@ -0,0 +1,65 @@ +--------------------------------------------------------------------- +-- TITLE: Shifter Unit +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- Matthias Gruenewald +-- DATE CREATED: 2/2/01 +-- FILENAME: shifter.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements the 32-bit shifter unit. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; + +entity shifter is + generic(shifter_type : string := "DEFAULT"); + port(value : in std_logic_vector(31 downto 0); + shift_amount : in std_logic_vector(4 downto 0); + shift_func : in shift_function_type; + c_shift : out std_logic_vector(31 downto 0)); +end; --entity shifter + +architecture logic of shifter is +-- type shift_function_type is ( +-- shift_nothing, shift_left_unsigned, +-- shift_right_signed, shift_right_unsigned); + +signal shift1L, shift2L, shift4L, shift8L, shift16L : std_logic_vector(31 downto 0); +signal shift1R, shift2R, shift4R, shift8R, shift16R : std_logic_vector(31 downto 0); +signal fills : std_logic_vector(31 downto 16); + +begin + fills <= "1111111111111111" when shift_func = SHIFT_RIGHT_SIGNED + and value(31) = '1' + else "0000000000000000"; + shift1L <= value(30 downto 0) & '0' when shift_amount(0) = '1' else value; + shift2L <= shift1L(29 downto 0) & "00" when shift_amount(1) = '1' else shift1L; + shift4L <= shift2L(27 downto 0) & "0000" when shift_amount(2) = '1' else shift2L; + shift8L <= shift4L(23 downto 0) & "00000000" when shift_amount(3) = '1' else shift4L; + shift16L <= shift8L(15 downto 0) & ZERO(15 downto 0) when shift_amount(4) = '1' else shift8L; + + shift1R <= fills(31) & value(31 downto 1) when shift_amount(0) = '1' else value; + shift2R <= fills(31 downto 30) & shift1R(31 downto 2) when shift_amount(1) = '1' else shift1R; + shift4R <= fills(31 downto 28) & shift2R(31 downto 4) when shift_amount(2) = '1' else shift2R; + shift8R <= fills(31 downto 24) & shift4R(31 downto 8) when shift_amount(3) = '1' else shift4R; + shift16R <= fills(31 downto 16) & shift8R(31 downto 16) when shift_amount(4) = '1' else shift8R; + +GENERIC_SHIFTER: if shifter_type = "DEFAULT" generate + c_shift <= shift16L when shift_func = SHIFT_LEFT_UNSIGNED else + shift16R when shift_func = SHIFT_RIGHT_UNSIGNED or + shift_func = SHIFT_RIGHT_SIGNED else + ZERO; +end generate; + +AREA_OPTIMIZED_SHIFTER: if shifter_type /= "DEFAULT" generate + c_shift <= shift16L when shift_func = SHIFT_LEFT_UNSIGNED else (others => 'Z'); + c_shift <= shift16R when shift_func = SHIFT_RIGHT_UNSIGNED or + shift_func = SHIFT_RIGHT_SIGNED else (others => 'Z'); + c_shift <= ZERO when shift_func = SHIFT_NOTHING else (others => 'Z'); +end generate; + +end; --architecture logic + diff --git a/vhdl/simili.cmd b/vhdl/simili.cmd new file mode 100755 index 0000000..bf46409 --- /dev/null +++ b/vhdl/simili.cmd @@ -0,0 +1,8 @@ +add list /u1/* +#add list /u1/u1_cpu/* +#add list /u1/u1_cpu/u8_mult/* +#add list /u1/u1_cpu/pc /u1/u1_cpu/opcode /u1/* +#add list /u1/u1_cpu/u3_control/* +#add list /u1/u1_cpu/u8_mult/* +SetListStyle nodelta collapse +SetListInterval 0us 1ms diff --git a/vhdl/spartan3e.ucf b/vhdl/spartan3e.ucf new file mode 100644 index 0000000..04c0b2d --- /dev/null +++ b/vhdl/spartan3e.ucf @@ -0,0 +1,279 @@ +##################################################### +### SPARTAN-3E STARTER KIT BOARD CONSTRAINTS FILE +##################################################### +# ==== Analog-to-Digital Converter (ADC) ==== +# some connections shared with SPI Flash, DAC, ADC, and AMP +#NET "AD_CONV" LOC = "P11" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; +# ==== Programmable Gain Amplifier (AMP) ==== +# some connections shared with SPI Flash, DAC, ADC, and AMP +#NET "AMP_CS" LOC = "N7" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; +#NET "AMP_DOUT" LOC = "E18" | IOSTANDARD = LVCMOS33 ; +#NET "AMP_SHDN" LOC = "P7" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; +# ==== Pushbuttons (BTN) ==== +NET "BTN_EAST" LOC = "H13" | IOSTANDARD = LVTTL | PULLDOWN ; +NET "BTN_NORTH" LOC = "V4" | IOSTANDARD = LVTTL | PULLDOWN ; +NET "BTN_SOUTH" LOC = "K17" | IOSTANDARD = LVTTL | PULLDOWN ; +NET "BTN_WEST" LOC = "D18" | IOSTANDARD = LVTTL | PULLDOWN ; +# ==== Clock inputs (CLK) ==== +NET "CLK_50MHZ" LOC = "C9" | IOSTANDARD = LVCMOS33 ; +# Define clock period for 50 MHz oscillator (40%/60% duty-cycle) +NET "CLK_50MHZ" PERIOD = 20 ns HIGH 40 %; +#NET "CLK_AUX" LOC = "B8" | IOSTANDARD = LVCMOS33 ; +#NET "CLK_SMA" LOC = "A10" | IOSTANDARD = LVCMOS33 ; +# ==== Digital-to-Analog Converter (DAC) ==== +# some connections shared with SPI Flash, DAC, ADC, and AMP +#NET "DAC_CLR" LOC = "P8" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +#NET "DAC_CS" LOC = "N8" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +# ==== 1-Wire Secure EEPROM (DS) +#NET "DS_WIRE" LOC = "U4" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +# ==== Ethernet PHY (E) ==== +#NET "E_COL" LOC = "U6" | IOSTANDARD = LVCMOS33 ; +#NET "E_CRS" LOC = "U13" | IOSTANDARD = LVCMOS33 ; +NET "E_MDC" LOC = "P9" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +NET "E_MDIO" LOC = "U5" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +NET "E_RX_CLK" LOC = "V3" | IOSTANDARD = LVCMOS33 ; +NET "E_RX_DV" LOC = "V2" | IOSTANDARD = LVCMOS33 ; +NET "E_RXD<0>" LOC = "V8" | IOSTANDARD = LVCMOS33 ; +NET "E_RXD<1>" LOC = "T11" | IOSTANDARD = LVCMOS33 ; +NET "E_RXD<2>" LOC = "U11" | IOSTANDARD = LVCMOS33 ; +NET "E_RXD<3>" LOC = "V14" | IOSTANDARD = LVCMOS33 ; +#NET "E_RXD<4>" LOC = "U14" | IOSTANDARD = LVCMOS33 ; +NET "E_TX_CLK" LOC = "T7" | IOSTANDARD = LVCMOS33 ; +NET "E_TX_EN" LOC = "P15" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +NET "E_TXD<0>" LOC = "R11" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +NET "E_TXD<1>" LOC = "T15" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +NET "E_TXD<2>" LOC = "R5" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +NET "E_TXD<3>" LOC = "T5" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +#NET "E_TXD<4>" LOC = "R6" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +# ==== FPGA Configuration Mode, INIT_B Pins (FPGA) ==== +#NET "FPGA_M0" LOC = "M10" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +#NET "FPGA_M1" LOC = "V11" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +#NET "FPGA_M2" LOC = "T10" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; +#NET "FPGA_INIT_B" LOC = "T3" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 4 ; +#NET "FPGA_RDWR_B" LOC = "U10" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 4 ; +#NET "FPGA_HSWAP" LOC = "B3" | IOSTANDARD = LVCMOS33 ; +# ==== FX2 Connector (FX2) ==== +#NET "FX2_CLKIN" LOC = "E10" | IOSTANDARD = LVCMOS33 ; +#NET "FX2_CLKIO" LOC = "D9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_CLKOUT" LOC = "D10" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +# These four connections are shared with the J1 6-pin accessory header +#NET "FX2_IO<1>" LOC = "B4" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<2>" LOC = "A4" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<3>" LOC = "D5" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<4>" LOC = "C5" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +# These four connections are shared with the J2 6-pin accessory header +#NET "FX2_IO<5>" LOC = "A6" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<6>" LOC = "B6" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<7>" LOC = "E7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<8>" LOC = "F7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +# These four connections are shared with the J4 6-pin accessory header +#NET "FX2_IO<9>" LOC = "D7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<10>" LOC = "C7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<11>" LOC = "F8" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<12>" LOC = "E8" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +# The discrete LEDs are shared with the following 8 FX2 connections +#NET "FX2_IO<13>" LOC = "F9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<14>" LOC = "E9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<15>" LOC = "D11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<16>" LOC = "C11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<17>" LOC = "F11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<18>" LOC = "E11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<19>" LOC = "E12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<20>" LOC = "F12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<21>" LOC = "A13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<22>" LOC = "B13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<23>" LOC = "A14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<24>" LOC = "B14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<25>" LOC = "C14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<26>" LOC = "D14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<27>" LOC = "A16" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<28>" LOC = "B16" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<29>" LOC = "E13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<30>" LOC = "C4" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<31>" LOC = "B11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<32>" LOC = "A11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<33>" LOC = "A8" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<34>" LOC = "G9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IP<35>" LOC = "D12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IP<36>" LOC = "C12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IP<37>" LOC = "A15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IP<38>" LOC = "B15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IO<39>" LOC = "C3" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +#NET "FX2_IP<40>" LOC = "C15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; +# ==== 6-pin header J1 ==== +# These are shared connections with the FX2 connector +#NET "J1<0>" LOC = "B4" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J1<1>" LOC = "A4" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J1<2>" LOC = "D5" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J1<3>" LOC = "C5" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +# ==== 6-pin header J2 ==== +# These are shared connections with the FX2 connector +#NET "J2<0>" LOC = "A6" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J2<1>" LOC = "B6" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J2<2>" LOC = "E7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J2<3>" LOC = "F7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +# ==== 6-pin header J4 ==== +# These are shared connections with the FX2 connector +#NET "J4<0>" LOC = "D7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J4<1>" LOC = "C7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J4<2>" LOC = "F8" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +#NET "J4<3>" LOC = "E8" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; +# ==== Character LCD (LCD) ==== +#NET "LCD_E" LOC = "M18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +#NET "LCD_RS" LOC = "L18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +#NET "LCD_RW" LOC = "L17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +# LCD data connections are shared with StrataFlash connections SF_D<11:8> +#NET "SF_D<8>" LOC = "R15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +#NET "SF_D<9>" LOC = "R16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +#NET "SF_D<10>" LOC = "P17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +#NET "SF_D<11>" LOC = "M15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +# ==== Discrete LEDs (LED) ==== +# These are shared connections with the FX2 connector +NET "LED<0>" LOC = "F12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +NET "LED<1>" LOC = "E12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +NET "LED<2>" LOC = "E11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +NET "LED<3>" LOC = "F11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +NET "LED<4>" LOC = "C11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +NET "LED<5>" LOC = "D11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +NET "LED<6>" LOC = "E9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +NET "LED<7>" LOC = "F9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; +# ==== PS/2 Mouse/Keyboard Port (PS2) ==== +NET "PS2_CLK" LOC = "G14" | IOSTANDARD = LVCMOS33 ; +NET "PS2_DATA" LOC = "G13" | IOSTANDARD = LVCMOS33 ; +# ==== Rotary Pushbutton Switch (ROT) ==== +NET "ROT_A" LOC = "K18" | IOSTANDARD = LVTTL | PULLUP ; +NET "ROT_B" LOC = "G18" | IOSTANDARD = LVTTL | PULLUP ; +NET "ROT_CENTER" LOC = "V16" | IOSTANDARD = LVTTL | PULLDOWN ; +# ==== RS-232 Serial Ports (RS232) ==== +NET "RS232_DCE_RXD" LOC = "R7" | IOSTANDARD = LVTTL ; +NET "RS232_DCE_TXD" LOC = "M14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = SLOW ; +#NET "RS232_DTE_RXD" LOC = "U8" | IOSTANDARD = LVTTL ; +#NET "RS232_DTE_TXD" LOC = "M13" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = SLOW ; +# ==== DDR SDRAM (SD) ==== (I/O Bank 3, VCCO=2.5V) +NET "SD_A<0>" LOC = "T1" | IOSTANDARD = SSTL2_I ; +NET "SD_A<1>" LOC = "R3" | IOSTANDARD = SSTL2_I ; +NET "SD_A<2>" LOC = "R2" | IOSTANDARD = SSTL2_I ; +NET "SD_A<3>" LOC = "P1" | IOSTANDARD = SSTL2_I ; +NET "SD_A<4>" LOC = "F4" | IOSTANDARD = SSTL2_I ; +NET "SD_A<5>" LOC = "H4" | IOSTANDARD = SSTL2_I ; +NET "SD_A<6>" LOC = "H3" | IOSTANDARD = SSTL2_I ; +NET "SD_A<7>" LOC = "H1" | IOSTANDARD = SSTL2_I ; +NET "SD_A<8>" LOC = "H2" | IOSTANDARD = SSTL2_I ; +NET "SD_A<9>" LOC = "N4" | IOSTANDARD = SSTL2_I ; +NET "SD_A<10>" LOC = "T2" | IOSTANDARD = SSTL2_I ; +NET "SD_A<11>" LOC = "N5" | IOSTANDARD = SSTL2_I ; +NET "SD_A<12>" LOC = "P2" | IOSTANDARD = SSTL2_I ; +NET "SD_BA<0>" LOC = "K5" | IOSTANDARD = SSTL2_I ; +NET "SD_BA<1>" LOC = "K6" | IOSTANDARD = SSTL2_I ; +NET "SD_CAS" LOC = "C2" | IOSTANDARD = SSTL2_I ; +NET "SD_CK_N" LOC = "J4" | IOSTANDARD = SSTL2_I ; +NET "SD_CK_P" LOC = "J5" | IOSTANDARD = SSTL2_I ; +NET "SD_CKE" LOC = "K3" | IOSTANDARD = SSTL2_I ; +NET "SD_CS" LOC = "K4" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<0>" LOC = "L2" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<1>" LOC = "L1" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<2>" LOC = "L3" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<3>" LOC = "L4" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<4>" LOC = "M3" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<5>" LOC = "M4" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<6>" LOC = "M5" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<7>" LOC = "M6" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<8>" LOC = "E2" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<9>" LOC = "E1" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<10>" LOC = "F1" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<11>" LOC = "F2" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<12>" LOC = "G6" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<13>" LOC = "G5" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<14>" LOC = "H6" | IOSTANDARD = SSTL2_I ; +NET "SD_DQ<15>" LOC = "H5" | IOSTANDARD = SSTL2_I ; +NET "SD_LDM" LOC = "J2" | IOSTANDARD = SSTL2_I ; +NET "SD_LDQS" LOC = "L6" | IOSTANDARD = SSTL2_I ; +NET "SD_RAS" LOC = "C1" | IOSTANDARD = SSTL2_I ; +NET "SD_UDM" LOC = "J1" | IOSTANDARD = SSTL2_I ; +NET "SD_UDQS" LOC = "G3" | IOSTANDARD = SSTL2_I ; +NET "SD_WE" LOC = "D1" | IOSTANDARD = SSTL2_I ; +# Path to allow connection to top DCM connection +#NET "SD_CK_FB" LOC = "B9" | IOSTANDARD = LVCMOS33 ; +# Prohibit VREF pins +CONFIG PROHIBIT = D2; +CONFIG PROHIBIT = G4; +CONFIG PROHIBIT = J6; +CONFIG PROHIBIT = L5; +CONFIG PROHIBIT = R4; +# ==== Intel StrataFlash Parallel NOR Flash (SF) ==== +NET "SF_A<0>" LOC = "H17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<1>" LOC = "J13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<2>" LOC = "J12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<3>" LOC = "J14" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<4>" LOC = "J15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<5>" LOC = "J16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<6>" LOC = "J17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<7>" LOC = "K14" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<8>" LOC = "K15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<9>" LOC = "K12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<10>" LOC = "K13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<11>" LOC = "L15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<12>" LOC = "L16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<13>" LOC = "T18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<14>" LOC = "R18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<15>" LOC = "T17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<16>" LOC = "U18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<17>" LOC = "T16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<18>" LOC = "U15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<19>" LOC = "V15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<20>" LOC = "T12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<21>" LOC = "V13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<22>" LOC = "V12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<23>" LOC = "N11" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_A<24>" LOC = "A11" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_BYTE" LOC = "C17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_CE0" LOC = "D16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<1>" LOC = "P10" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<2>" LOC = "R10" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<3>" LOC = "V9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<4>" LOC = "U9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<5>" LOC = "R9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<6>" LOC = "M9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<7>" LOC = "N9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<8>" LOC = "R15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<9>" LOC = "R16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<10>" LOC = "P17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<11>" LOC = "M15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<12>" LOC = "M16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<13>" LOC = "P6" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<14>" LOC = "R8" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_D<15>" LOC = "T8" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_OE" LOC = "C18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "SF_STS" LOC = "B18" | IOSTANDARD = LVCMOS33 ; +NET "SF_WE" LOC = "D17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +# ==== STMicro SPI serial Flash (SPI) ==== +# some connections shared with SPI Flash, DAC, ADC, and AMP +NET "SPI_MISO" LOC = "N10" | IOSTANDARD = LVCMOS33 ; +#NET "SPI_MOSI" LOC = "T4" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; +#NET "SPI_SCK" LOC = "U16" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; +#NET "SPI_SS_B" LOC = "U3" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; +#NET "SPI_ALT_CS_JP11" LOC = "R12" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; +# ==== Slide Switches (SW) ==== +NET "SW<0>" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ; +NET "SW<1>" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ; +NET "SW<2>" LOC = "H18" | IOSTANDARD = LVTTL | PULLUP ; +NET "SW<3>" LOC = "N17" | IOSTANDARD = LVTTL | PULLUP ; +# ==== VGA Port (VGA) ==== +NET "VGA_BLUE" LOC = "G15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; +NET "VGA_GREEN" LOC = "H15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; +NET "VGA_HSYNC" LOC = "F15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; +NET "VGA_RED" LOC = "H14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; +NET "VGA_VSYNC" LOC = "F14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; +# ==== Xilinx CPLD (XC) ==== +#NET "XC_CMD<0>" LOC = "P18" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; +#NET "XC_CMD<1>" LOC = "N18" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; +#NET "XC_CPLD_EN" LOC = "B10" | IOSTANDARD = LVTTL ; +#NET "XC_D<0>" LOC = "G16" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; +#NET "XC_D<1>" LOC = "F18" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; +#NET "XC_D<2>" LOC = "F17" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; +#NET "XC_TRIG" LOC = "R17" | IOSTANDARD = LVCMOS33 ; +#NET "XC_GCK0" LOC = "H16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +#NET "GCLK10" LOC = "C9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; +NET "CLK_50MHZ" TNM_NET = "CLK_50MHZ"; +NET "clk_reg1" TNM_NET = "clk_reg1"; +TIMESPEC "TS_clk_reg1" = PERIOD "clk_reg1" 40 ns HIGH 50 %; diff --git a/vhdl/tbench.vhd b/vhdl/tbench.vhd new file mode 100644 index 0000000..700c123 --- /dev/null +++ b/vhdl/tbench.vhd @@ -0,0 +1,119 @@ +--------------------------------------------------------------------- +-- TITLE: Test Bench +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 4/21/01 +-- FILENAME: tbench.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- This entity provides a test bench for testing the Plasma CPU core. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mlite_pack.all; +use ieee.std_logic_unsigned.all; + +entity tbench is +end; --entity tbench + +architecture logic of tbench is + constant memory_type : string := + "TRI_PORT_X"; +-- "DUAL_PORT_"; +-- "ALTERA_LPM"; +-- "XILINX_16X"; + + constant log_file : string := +-- "UNUSED"; + "output.txt"; + + signal clk : std_logic := '1'; + signal reset : std_logic := '1'; + signal interrupt : std_logic := '0'; + signal mem_write : std_logic; + signal address : std_logic_vector(31 downto 2); + signal data_write : std_logic_vector(31 downto 0); + signal data_read : std_logic_vector(31 downto 0); + signal pause1 : std_logic := '0'; + signal pause2 : std_logic := '0'; + signal pause : std_logic; + signal no_ddr_start: std_logic; + signal no_ddr_stop : std_logic; + signal byte_we : std_logic_vector(3 downto 0); + signal uart_write : std_logic; + signal gpioA_in : std_logic_vector(31 downto 0) := (others => '0'); +begin --architecture + --Uncomment the line below to test interrupts + interrupt <= '1' after 20 us when interrupt = '0' else '0' after 445 ns; + + clk <= not clk after 50 ns; + reset <= '0' after 500 ns; + pause1 <= '1' after 700 ns when pause1 = '0' else '0' after 200 ns; + pause2 <= '1' after 300 ns when pause2 = '0' else '0' after 200 ns; + pause <= pause1 or pause2; + gpioA_in(20) <= not gpioA_in(20) after 200 ns; --E_RX_CLK + gpioA_in(19) <= not gpioA_in(19) after 20 us; --E_RX_DV + gpioA_in(18 downto 15) <= gpioA_in(18 downto 15) + 1 after 400 ns; --E_RX_RXD + gpioA_in(14) <= not gpioA_in(14) after 200 ns; --E_TX_CLK + + u1_plasma: plasma + generic map (memory_type => memory_type, + ethernet => '1', + use_cache => '1', + log_file => log_file) + PORT MAP ( + clk => clk, + reset => reset, + uart_read => uart_write, + uart_write => uart_write, + + address => address, + byte_we => byte_we, + data_write => data_write, + data_read => data_read, + mem_pause_in => pause, + no_ddr_start => no_ddr_start, + no_ddr_stop => no_ddr_stop, + + gpio0_out => open, + gpioA_in => gpioA_in); + + dram_proc: process(clk, address, byte_we, data_write, pause) + constant ADDRESS_WIDTH : natural := 16; + type storage_array is + array(natural range 0 to (2 ** ADDRESS_WIDTH) / 4 - 1) of + std_logic_vector(31 downto 0); + variable storage : storage_array; + variable data : std_logic_vector(31 downto 0); + variable index : natural := 0; + begin + index := conv_integer(address(ADDRESS_WIDTH-1 downto 2)); + data := storage(index); + + if byte_we(0) = '1' then + data(7 downto 0) := data_write(7 downto 0); + end if; + if byte_we(1) = '1' then + data(15 downto 8) := data_write(15 downto 8); + end if; + if byte_we(2) = '1' then + data(23 downto 16) := data_write(23 downto 16); + end if; + if byte_we(3) = '1' then + data(31 downto 24) := data_write(31 downto 24); + end if; + + if rising_edge(clk) then + if address(30 downto 28) = "001" and byte_we /= "0000" then + storage(index) := data; + end if; + end if; + + if pause = '0' then + data_read <= data; + end if; + end process; + + +end; --architecture logic diff --git a/vhdl/uart.vhd b/vhdl/uart.vhd new file mode 100644 index 0000000..5f576fe --- /dev/null +++ b/vhdl/uart.vhd @@ -0,0 +1,181 @@ +--------------------------------------------------------------------- +-- TITLE: UART +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 5/29/02 +-- FILENAME: uart.vhd +-- PROJECT: Plasma CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements the UART. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_misc.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; +use ieee.std_logic_unsigned.all; +use std.textio.all; +use work.mlite_pack.all; + +entity uart is + generic(log_file : string := "UNUSED"); + port(clk : in std_logic; + reset : in std_logic; + enable_read : in std_logic; + enable_write : in std_logic; + data_in : in std_logic_vector(7 downto 0); + data_out : out std_logic_vector(7 downto 0); + uart_read : in std_logic; + uart_write : out std_logic; + busy_write : out std_logic; + data_avail : out std_logic); +end; --entity uart + +architecture logic of uart is + signal delay_write_reg : std_logic_vector(9 downto 0); + signal bits_write_reg : std_logic_vector(3 downto 0); + signal data_write_reg : std_logic_vector(8 downto 0); + signal delay_read_reg : std_logic_vector(9 downto 0); + signal bits_read_reg : std_logic_vector(3 downto 0); + signal data_read_reg : std_logic_vector(7 downto 0); + signal data_save_reg : std_logic_vector(17 downto 0); + signal busy_write_sig : std_logic; + signal read_value_reg : std_logic_vector(6 downto 0); + signal uart_read2 : std_logic; + +begin + +uart_proc: process(clk, reset, enable_read, enable_write, data_in, + data_write_reg, bits_write_reg, delay_write_reg, + data_read_reg, bits_read_reg, delay_read_reg, + data_save_reg, read_value_reg, uart_read2, + busy_write_sig, uart_read) + constant COUNT_VALUE : std_logic_vector(9 downto 0) := +-- "0100011110"; --33MHz/2/57600Hz = 0x11e +-- "1101100100"; --50MHz/57600Hz = 0x364 + "0110110010"; --25MHz/57600Hz = 0x1b2 -- Plasma IF uses div2 +-- "0011011001"; --12.5MHz/57600Hz = 0xd9 +-- "0000000100"; --for debug (shorten read_value_reg) +begin + uart_read2 <= read_value_reg(read_value_reg'length - 1); + + if reset = '1' then + data_write_reg <= ZERO(8 downto 1) & '1'; + bits_write_reg <= "0000"; + delay_write_reg <= ZERO(9 downto 0); + read_value_reg <= ONES(read_value_reg'length-1 downto 0); + data_read_reg <= ZERO(7 downto 0); + bits_read_reg <= "0000"; + delay_read_reg <= ZERO(9 downto 0); + data_save_reg <= ZERO(17 downto 0); + elsif rising_edge(clk) then + + --Write UART + if bits_write_reg = "0000" then --nothing left to write? + if enable_write = '1' then + delay_write_reg <= ZERO(9 downto 0); --delay before next bit + bits_write_reg <= "1010"; --number of bits to write + data_write_reg <= data_in & '0'; --remember data & start bit + end if; + else + if delay_write_reg /= COUNT_VALUE then + delay_write_reg <= delay_write_reg + 1; --delay before next bit + else + delay_write_reg <= ZERO(9 downto 0); --reset delay + bits_write_reg <= bits_write_reg - 1; --bits left to write + data_write_reg <= '1' & data_write_reg(8 downto 1); + end if; + end if; + + --Average uart_read signal + if uart_read = '1' then + if read_value_reg /= ONES(read_value_reg'length - 1 downto 0) then + read_value_reg <= read_value_reg + 1; + end if; + else + if read_value_reg /= ZERO(read_value_reg'length - 1 downto 0) then + read_value_reg <= read_value_reg - 1; + end if; + end if; + + --Read UART + if delay_read_reg = ZERO(9 downto 0) then --done delay for read? + if bits_read_reg = "0000" then --nothing left to read? + if uart_read2 = '0' then --wait for start bit + delay_read_reg <= '0' & COUNT_VALUE(9 downto 1); --half period + bits_read_reg <= "1001"; --bits left to read + end if; + else + delay_read_reg <= COUNT_VALUE; --initialize delay + bits_read_reg <= bits_read_reg - 1; --bits left to read + data_read_reg <= uart_read2 & data_read_reg(7 downto 1); + end if; + else + delay_read_reg <= delay_read_reg - 1; --delay + end if; + + --Control character buffer + if bits_read_reg = "0000" and delay_read_reg = COUNT_VALUE then + if data_save_reg(8) = '0' or + (enable_read = '1' and data_save_reg(17) = '0') then + --Empty buffer + data_save_reg(8 downto 0) <= '1' & data_read_reg; + else + --Second character in buffer + data_save_reg(17 downto 9) <= '1' & data_read_reg; + if enable_read = '1' then + data_save_reg(8 downto 0) <= data_save_reg(17 downto 9); + end if; + end if; + elsif enable_read = '1' then + data_save_reg(17) <= '0'; --data_available + data_save_reg(8 downto 0) <= data_save_reg(17 downto 9); + end if; + end if; --rising_edge(clk) + + uart_write <= data_write_reg(0); + if bits_write_reg /= "0000" +-- Comment out the following line for full UART simulation (much slower) + and log_file = "UNUSED" + then + busy_write_sig <= '1'; + else + busy_write_sig <= '0'; + end if; + busy_write <= busy_write_sig; + data_avail <= data_save_reg(8); + data_out <= data_save_reg(7 downto 0); + +end process; --uart_proc + +-- synthesis_off + uart_logger: + if log_file /= "UNUSED" generate + uart_proc: process(clk, enable_write, data_in) + file store_file : text open write_mode is log_file; + variable hex_file_line : line; + variable c : character; + variable index : natural; + variable line_length : natural := 0; + begin + if rising_edge(clk) and busy_write_sig = '0' then + if enable_write = '1' then + index := conv_integer(data_in(6 downto 0)); + if index /= 10 then + c := character'val(index); + write(hex_file_line, c); + line_length := line_length + 1; + end if; + if index = 10 or line_length >= 72 then +--The following line may have to be commented out for synthesis + writeline(store_file, hex_file_line); + line_length := 0; + end if; + end if; --uart_sel + end if; --rising_edge(clk) + end process; --uart_proc + end generate; --uart_logger +-- synthesis_on + +end; --architecture logic -- 2.39.2