From a168a7d93af8d3cece8992f1cad633378e943274 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 21 Aug 2024 22:25:51 +0100 Subject: [PATCH 01/88] set up basic freertos project --- freertos/app/CMakeLists.txt | 22 + freertos/app/freertos_config/CMakeLists.txt | 15 + .../freertos_config/include/FreeRTOSConfig.h | 648 ++++++++++++++++++ 3 files changed, 685 insertions(+) create mode 100644 freertos/app/CMakeLists.txt create mode 100644 freertos/app/freertos_config/CMakeLists.txt create mode 100644 freertos/app/freertos_config/include/FreeRTOSConfig.h diff --git a/freertos/app/CMakeLists.txt b/freertos/app/CMakeLists.txt new file mode 100644 index 0000000..b83ad5f --- /dev/null +++ b/freertos/app/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.12 FATAL_ERROR) + +project(crush_freertos) + +include(FetchContent) + +FetchContent_Declare( freertos_kernel + GIT_REPOSITORY https://github.com/FreeRTOS/FreeRTOS-Kernel.git + GIT_TAG V11.1.0 +) + +add_subdirectory(freertos_config) + +set( FREERTOS_HEAP "4" CACHE STRING "" FORCE) +# Select the native compile PORT +set( FREERTOS_PORT "GCC_POSIX" CACHE STRING "" FORCE) +# Select the cross-compile PORT +if (CMAKE_CROSSCOMPILING) + set(FREERTOS_PORT "GCC_ARM_CA9" CACHE STRING "" FORCE) +endif() + +FetchContent_MakeAvailable(freertos_kernel) diff --git a/freertos/app/freertos_config/CMakeLists.txt b/freertos/app/freertos_config/CMakeLists.txt new file mode 100644 index 0000000..c94d2ad --- /dev/null +++ b/freertos/app/freertos_config/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(freertos_config INTERFACE) + +target_include_directories(freertos_config SYSTEM +INTERFACE + include +) + +target_compile_definitions(freertos_config + INTERFACE + projCOVERAGE_TEST=0 +) + +# options for cross-compilation or something like that? +target_compile_definitions(freertos_config INTERFACE ${definitions}) +target_compile_options(freertos_config INTERFACE ${options}) diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h new file mode 100644 index 0000000..33f80ea --- /dev/null +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -0,0 +1,648 @@ +/* + * FreeRTOS Kernel V11.1.0 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/******************************************************************************* + * This file provides an example FreeRTOSConfig.h header file, inclusive of an + * abbreviated explanation of each configuration item. Online and reference + * documentation provides more information. + * https://www.freertos.org/a00110.html + * + * Constant values enclosed in square brackets ('[' and ']') must be completed + * before this file will build. + * + * Use the FreeRTOSConfig.h supplied with the RTOS port in use rather than this + * generic file, if one is available. + ******************************************************************************/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/******************************************************************************/ +/* Hardware description related definitions. **********************************/ +/******************************************************************************/ + +/* In most cases, configCPU_CLOCK_HZ must be set to the frequency of the clock + * that drives the peripheral used to generate the kernels periodic tick interrupt. + * The default value is set to 20MHz and matches the QEMU demo settings. Your + * application will certainly need a different value so set this correctly. + * This is very often, but not always, equal to the main system clock frequency. */ +#define configCPU_CLOCK_HZ ( ( unsigned long ) 20000000 ) + +/* configSYSTICK_CLOCK_HZ is an optional parameter for ARM Cortex-M ports only. + * + * By default ARM Cortex-M ports generate the RTOS tick interrupt from the + * Cortex-M SysTick timer. Most Cortex-M MCUs run the SysTick timer at the same + * frequency as the MCU itself - when that is the case configSYSTICK_CLOCK_HZ is + * not needed and should be left undefined. If the SysTick timer is clocked at a + * different frequency to the MCU core then set configCPU_CLOCK_HZ to the MCU clock + * frequency, as normal, and configSYSTICK_CLOCK_HZ to the SysTick clock + * frequency. Not used if left undefined. + * The default value is undefined (commented out). If you need this value bring it + * back and set it to a suitable value. */ + +/* + #define configSYSTICK_CLOCK_HZ [Platform specific] + */ + +/******************************************************************************/ +/* Scheduling behaviour related definitions. **********************************/ +/******************************************************************************/ + +/* configTICK_RATE_HZ sets frequency of the tick interrupt in Hz, normally + * calculated from the configCPU_CLOCK_HZ value. */ +#define configTICK_RATE_HZ 100 + +/* Set configUSE_PREEMPTION to 1 to use pre-emptive scheduling. Set + * configUSE_PREEMPTION to 0 to use co-operative scheduling. + * See https://www.freertos.org/single-core-amp-smp-rtos-scheduling.html. */ +#define configUSE_PREEMPTION 1 + +/* Set configUSE_TIME_SLICING to 1 to have the scheduler switch between Ready + * state tasks of equal priority on every tick interrupt. Set + * configUSE_TIME_SLICING to 0 to prevent the scheduler switching between Ready + * state tasks just because there was a tick interrupt. See + * https://freertos.org/single-core-amp-smp-rtos-scheduling.html. */ +#define configUSE_TIME_SLICING 0 + +/* Set configUSE_PORT_OPTIMISED_TASK_SELECTION to 1 to select the next task to + * run using an algorithm optimised to the instruction set of the target hardware - + * normally using a count leading zeros assembly instruction. Set to 0 to select + * the next task to run using a generic C algorithm that works for all FreeRTOS + * ports. Not all FreeRTOS ports have this option. Defaults to 0 if left + * undefined. */ +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 + +/* Set configUSE_TICKLESS_IDLE to 1 to use the low power tickless mode. Set to + * 0 to keep the tick interrupt running at all times. Not all FreeRTOS ports + * support tickless mode. See https://www.freertos.org/low-power-tickless-rtos.html + * Defaults to 0 if left undefined. */ +#define configUSE_TICKLESS_IDLE 0 + +/* configMAX_PRIORITIES Sets the number of available task priorities. Tasks can + * be assigned priorities of 0 to (configMAX_PRIORITIES - 1). Zero is the lowest + * priority. */ +#define configMAX_PRIORITIES 5 + +/* configMINIMAL_STACK_SIZE defines the size of the stack used by the Idle task + * (in words, not in bytes!). The kernel does not use this constant for any other + * purpose. Demo applications use the constant to make the demos somewhat portable + * across hardware architectures. */ +#define configMINIMAL_STACK_SIZE 128 + +/* configMAX_TASK_NAME_LEN sets the maximum length (in characters) of a task's + * human readable name. Includes the NULL terminator. */ +#define configMAX_TASK_NAME_LEN 16 + +/* Time is measured in 'ticks' - which is the number of times the tick interrupt + * has executed since the RTOS kernel was started. + * The tick count is held in a variable of type TickType_t. + * + * configTICK_TYPE_WIDTH_IN_BITS controls the type (and therefore bit-width) of TickType_t: + * + * Defining configTICK_TYPE_WIDTH_IN_BITS as TICK_TYPE_WIDTH_16_BITS causes + * TickType_t to be defined (typedef'ed) as an unsigned 16-bit type. + * + * Defining configTICK_TYPE_WIDTH_IN_BITS as TICK_TYPE_WIDTH_32_BITS causes + * TickType_t to be defined (typedef'ed) as an unsigned 32-bit type. + * + * Defining configTICK_TYPE_WIDTH_IN_BITS as TICK_TYPE_WIDTH_64_BITS causes + * TickType_t to be defined (typedef'ed) as an unsigned 64-bit type. */ +#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_64_BITS + +/* Set configIDLE_SHOULD_YIELD to 1 to have the Idle task yield to an + * application task if there is an Idle priority (priority 0) application task that + * can run. Set to 0 to have the Idle task use all of its timeslice. Default to 1 + * if left undefined. */ +#define configIDLE_SHOULD_YIELD 1 + +/* Each task has an array of task notifications. + * configTASK_NOTIFICATION_ARRAY_ENTRIES sets the number of indexes in the array. + * See https://www.freertos.org/RTOS-task-notifications.html Defaults to 1 if + * left undefined. */ +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 + +/* configQUEUE_REGISTRY_SIZE sets the maximum number of queues and semaphores + * that can be referenced from the queue registry. Only required when using a + * kernel aware debugger. Defaults to 0 if left undefined. */ +#define configQUEUE_REGISTRY_SIZE 0 + +/* Set configENABLE_BACKWARD_COMPATIBILITY to 1 to map function names and + * datatypes from old version of FreeRTOS to their latest equivalent. Defaults to + * 1 if left undefined. */ +#define configENABLE_BACKWARD_COMPATIBILITY 0 + +/* Each task has its own array of pointers that can be used as thread local + * storage. configNUM_THREAD_LOCAL_STORAGE_POINTERS set the number of indexes in + * the array. See https://www.freertos.org/thread-local-storage-pointers.html + * Defaults to 0 if left undefined. */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 + +/* When configUSE_MINI_LIST_ITEM is set to 0, MiniListItem_t and ListItem_t are + * both the same. When configUSE_MINI_LIST_ITEM is set to 1, MiniListItem_t contains + * 3 fewer fields than ListItem_t which saves some RAM at the cost of violating + * strict aliasing rules which some compilers depend on for optimization. Defaults + * to 1 if left undefined. */ +#define configUSE_MINI_LIST_ITEM 1 + +/* Sets the type used by the parameter to xTaskCreate() that specifies the stack + * size of the task being created. The same type is used to return information + * about stack usage in various other API calls. Defaults to size_t if left + * undefined. */ +#define configSTACK_DEPTH_TYPE size_t + +/* configMESSAGE_BUFFER_LENGTH_TYPE sets the type used to store the length of + * each message written to a FreeRTOS message buffer (the length is also written to + * the message buffer. Defaults to size_t if left undefined - but that may waste + * space if messages never go above a length that could be held in a uint8_t. */ +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t + +/* If configHEAP_CLEAR_MEMORY_ON_FREE is set to 1, then blocks of memory allocated + * using pvPortMalloc() will be cleared (i.e. set to zero) when freed using + * vPortFree(). Defaults to 0 if left undefined. */ +#define configHEAP_CLEAR_MEMORY_ON_FREE 1 + +/* vTaskList and vTaskGetRunTimeStats APIs take a buffer as a parameter and assume + * that the length of the buffer is configSTATS_BUFFER_MAX_LENGTH. Defaults to + * 0xFFFF if left undefined. + * New applications are recommended to use vTaskListTasks and + * vTaskGetRunTimeStatistics APIs instead and supply the length of the buffer + * explicitly to avoid memory corruption. */ +#define configSTATS_BUFFER_MAX_LENGTH 0xFFFF + +/* Set configUSE_NEWLIB_REENTRANT to 1 to have a newlib reent structure + * allocated for each task. Set to 0 to not support newlib reent structures. + * Default to 0 if left undefined. + * + * Note Newlib support has been included by popular demand, but is not used or + * tested by the FreeRTOS maintainers themselves. FreeRTOS is not responsible for + * resulting newlib operation. User must be familiar with newlib and must provide + * system-wide implementations of the necessary stubs. Note that (at the time of + * writing) the current newlib design implements a system-wide malloc() that must + * be provided with locks. */ +#define configUSE_NEWLIB_REENTRANT 0 + +/******************************************************************************/ +/* Software timer related definitions. ****************************************/ +/******************************************************************************/ + +/* Set configUSE_TIMERS to 1 to include software timer functionality in the + * build. Set to 0 to exclude software timer functionality from the build. The + * FreeRTOS/source/timers.c source file must be included in the build if + * configUSE_TIMERS is set to 1. Default to 0 if left undefined. See + * https://www.freertos.org/RTOS-software-timer.html. */ +#define configUSE_TIMERS 1 + +/* configTIMER_TASK_PRIORITY sets the priority used by the timer task. Only + * used if configUSE_TIMERS is set to 1. The timer task is a standard FreeRTOS + * task, so its priority is set like any other task. See + * https://www.freertos.org/RTOS-software-timer-service-daemon-task.html Only used + * if configUSE_TIMERS is set to 1. */ +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* configTIMER_TASK_STACK_DEPTH sets the size of the stack allocated to the + * timer task (in words, not in bytes!). The timer task is a standard FreeRTOS + * task. See https://www.freertos.org/RTOS-software-timer-service-daemon-task.html + * Only used if configUSE_TIMERS is set to 1. */ +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* configTIMER_QUEUE_LENGTH sets the length of the queue (the number of discrete + * items the queue can hold) used to send commands to the timer task. See + * https://www.freertos.org/RTOS-software-timer-service-daemon-task.html Only used + * if configUSE_TIMERS is set to 1. */ +#define configTIMER_QUEUE_LENGTH 10 + +/******************************************************************************/ +/* Event Group related definitions. *******************************************/ +/******************************************************************************/ + +/* Set configUSE_EVENT_GROUPS to 1 to include event group functionality in the + * build. Set to 0 to exclude event group functionality from the build. The + * FreeRTOS/source/event_groups.c source file must be included in the build if + * configUSE_EVENT_GROUPS is set to 1. Defaults to 1 if left undefined. */ + +#define configUSE_EVENT_GROUPS 1 + +/******************************************************************************/ +/* Stream Buffer related definitions. *****************************************/ +/******************************************************************************/ + +/* Set configUSE_STREAM_BUFFERS to 1 to include stream buffer functionality in + * the build. Set to 0 to exclude event group functionality from the build. The + * FreeRTOS/source/stream_buffer.c source file must be included in the build if + * configUSE_STREAM_BUFFERS is set to 1. Defaults to 1 if left undefined. */ + +#define configUSE_STREAM_BUFFERS 1 + +/******************************************************************************/ +/* Memory allocation related definitions. *************************************/ +/******************************************************************************/ + +/* Set configSUPPORT_STATIC_ALLOCATION to 1 to include FreeRTOS API functions + * that create FreeRTOS objects (tasks, queues, etc.) using statically allocated + * memory in the build. Set to 0 to exclude the ability to create statically + * allocated objects from the build. Defaults to 0 if left undefined. See + * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */ +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Set configSUPPORT_DYNAMIC_ALLOCATION to 1 to include FreeRTOS API functions + * that create FreeRTOS objects (tasks, queues, etc.) using dynamically allocated + * memory in the build. Set to 0 to exclude the ability to create dynamically + * allocated objects from the build. Defaults to 1 if left undefined. See + * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 + +/* Sets the total size of the FreeRTOS heap, in bytes, when heap_1.c, heap_2.c + * or heap_4.c are included in the build. This value is defaulted to 4096 bytes but + * it must be tailored to each application. Note the heap will appear in the .bss + * section. See https://www.freertos.org/a00111.html. */ +#define configTOTAL_HEAP_SIZE 4096 + +/* Set configAPPLICATION_ALLOCATED_HEAP to 1 to have the application allocate + * the array used as the FreeRTOS heap. Set to 0 to have the linker allocate the + * array used as the FreeRTOS heap. Defaults to 0 if left undefined. */ +#define configAPPLICATION_ALLOCATED_HEAP 0 + +/* Set configSTACK_ALLOCATION_FROM_SEPARATE_HEAP to 1 to have task stacks + * allocated from somewhere other than the FreeRTOS heap. This is useful if you + * want to ensure stacks are held in fast memory. Set to 0 to have task stacks + * come from the standard FreeRTOS heap. The application writer must provide + * implementations for pvPortMallocStack() and vPortFreeStack() if set to 1. + * Defaults to 0 if left undefined. */ +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +/* Set configENABLE_HEAP_PROTECTOR to 1 to enable bounds checking and obfuscation + * to internal heap block pointers in heap_4.c and heap_5.c to help catch pointer + * corruptions. Defaults to 0 if left undefined. */ +#define configENABLE_HEAP_PROTECTOR 0 + +/******************************************************************************/ +/* Interrupt nesting behaviour configuration. *********************************/ +/******************************************************************************/ + +/* configKERNEL_INTERRUPT_PRIORITY sets the priority of the tick and context + * switch performing interrupts. Not supported by all FreeRTOS ports. See + * https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific to + * ARM Cortex-M devices. */ +#define configKERNEL_INTERRUPT_PRIORITY 0 + +/* configMAX_SYSCALL_INTERRUPT_PRIORITY sets the interrupt priority above which + * FreeRTOS API calls must not be made. Interrupts above this priority are never + * disabled, so never delayed by RTOS activity. The default value is set to the + * highest interrupt priority (0). Not supported by all FreeRTOS ports. + * See https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific to + * ARM Cortex-M devices. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0 + +/* Another name for configMAX_SYSCALL_INTERRUPT_PRIORITY - the name used depends + * on the FreeRTOS port. */ +#define configMAX_API_CALL_INTERRUPT_PRIORITY 0 + +/******************************************************************************/ +/* Hook and callback function related definitions. ****************************/ +/******************************************************************************/ + +/* Set the following configUSE_* constants to 1 to include the named hook + * functionality in the build. Set to 0 to exclude the hook functionality from the + * build. The application writer is responsible for providing the hook function + * for any set to 1. See https://www.freertos.org/a00016.html. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 + +/* Set configUSE_SB_COMPLETED_CALLBACK to 1 to have send and receive completed + * callbacks for each instance of a stream buffer or message buffer. When the + * option is set to 1, APIs xStreamBufferCreateWithCallback() and + * xStreamBufferCreateStaticWithCallback() (and likewise APIs for message + * buffer) can be used to create a stream buffer or message buffer instance + * with application provided callbacks. Defaults to 0 if left undefined. */ +#define configUSE_SB_COMPLETED_CALLBACK 0 + +/* Set configCHECK_FOR_STACK_OVERFLOW to 1 or 2 for FreeRTOS to check for a + * stack overflow at the time of a context switch. Set to 0 to not look for a + * stack overflow. If configCHECK_FOR_STACK_OVERFLOW is 1 then the check only + * looks for the stack pointer being out of bounds when a task's context is saved + * to its stack - this is fast but somewhat ineffective. If + * configCHECK_FOR_STACK_OVERFLOW is 2 then the check looks for a pattern written + * to the end of a task's stack having been overwritten. This is slower, but will + * catch most (but not all) stack overflows. The application writer must provide + * the stack overflow callback when configCHECK_FOR_STACK_OVERFLOW is set to 1. + * See https://www.freertos.org/Stacks-and-stack-overflow-checking.html Defaults + * to 0 if left undefined. */ +#define configCHECK_FOR_STACK_OVERFLOW 2 + +/******************************************************************************/ +/* Run time and task stats gathering related definitions. *********************/ +/******************************************************************************/ + +/* Set configGENERATE_RUN_TIME_STATS to 1 to have FreeRTOS collect data on the + * processing time used by each task. Set to 0 to not collect the data. The + * application writer needs to provide a clock source if set to 1. Defaults to 0 + * if left undefined. See https://www.freertos.org/rtos-run-time-stats.html. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Set configUSE_TRACE_FACILITY to include additional task structure members + * are used by trace and visualisation functions and tools. Set to 0 to exclude + * the additional information from the structures. Defaults to 0 if left + * undefined. */ +#define configUSE_TRACE_FACILITY 0 + +/* Set to 1 to include the vTaskList() and vTaskGetRunTimeStats() functions in + * the build. Set to 0 to exclude these functions from the build. These two + * functions introduce a dependency on string formatting functions that would + * otherwise not exist - hence they are kept separate. Defaults to 0 if left + * undefined. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/******************************************************************************/ +/* Co-routine related definitions. ********************************************/ +/******************************************************************************/ + +/* Set configUSE_CO_ROUTINES to 1 to include co-routine functionality in the + * build, or 0 to omit co-routine functionality from the build. To include + * co-routines, croutine.c must be included in the project. Defaults to 0 if left + * undefined. */ +#define configUSE_CO_ROUTINES 0 + +/* configMAX_CO_ROUTINE_PRIORITIES defines the number of priorities available + * to the application co-routines. Any number of co-routines can share the same + * priority. Defaults to 0 if left undefined. */ +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +/******************************************************************************/ +/* Debugging assistance. ******************************************************/ +/******************************************************************************/ + +/* configASSERT() has the same semantics as the standard C assert(). It can + * either be defined to take an action when the assertion fails, or not defined + * at all (i.e. comment out or delete the definitions) to completely remove + * assertions. configASSERT() can be defined to anything you want, for example + * you can call a function if an assert fails that passes the filename and line + * number of the failing assert (for example, "vAssertCalled( __FILE__, __LINE__ )" + * or it can simple disable interrupts and sit in a loop to halt all execution + * on the failing line for viewing in a debugger. */ +#define configASSERT( x ) \ + if( ( x ) == 0 ) \ + { \ + taskDISABLE_INTERRUPTS(); \ + for( ; ; ) \ + ; \ + } + +/******************************************************************************/ +/* FreeRTOS MPU specific definitions. *****************************************/ +/******************************************************************************/ + +/* If configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS is set to 1 then + * the application writer can provide functions that execute in privileged mode. + * See: https://www.freertos.org/a00110.html#configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS + * Defaults to 0 if left undefined. Only used by the FreeRTOS Cortex-M MPU ports, + * not the standard ARMv7-M Cortex-M port. */ +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 + +/* Set configTOTAL_MPU_REGIONS to the number of MPU regions implemented on your + * target hardware. Normally 8 or 16. Only used by the FreeRTOS Cortex-M MPU + * ports, not the standard ARMv7-M Cortex-M port. Defaults to 8 if left + * undefined. */ +#define configTOTAL_MPU_REGIONS 8 + +/* configTEX_S_C_B_FLASH allows application writers to override the default + * values for the for TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for + * the MPU region covering Flash. Defaults to 0x07UL (which means TEX=000, S=1, + * C=1, B=1) if left undefined. Only used by the FreeRTOS Cortex-M MPU ports, not + * the standard ARMv7-M Cortex-M port. */ +#define configTEX_S_C_B_FLASH 0x07UL + +/* configTEX_S_C_B_SRAM allows application writers to override the default + * values for the for TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for + * the MPU region covering RAM. Defaults to 0x07UL (which means TEX=000, S=1, C=1, + * B=1) if left undefined. Only used by the FreeRTOS Cortex-M MPU ports, not + * the standard ARMv7-M Cortex-M port. */ +#define configTEX_S_C_B_SRAM 0x07UL + +/* Set configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY to 0 to prevent any privilege + * escalations originating from outside of the kernel code itself. Set to 1 to + * allow application tasks to raise privilege. Defaults to 1 if left undefined. + * Only used by the FreeRTOS Cortex-M MPU ports, not the standard ARMv7-M Cortex-M + * port. */ +#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1 + +/* Set configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS to 1 to allow unprivileged + * tasks enter critical sections (effectively mask interrupts). Set to 0 to + * prevent unprivileged tasks entering critical sections. Defaults to 1 if left + * undefined. Only used by the FreeRTOS Cortex-M MPU ports, not the standard + * ARMv7-M Cortex-M port. */ +#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 0 + +/* FreeRTOS Kernel version 10.6.0 introduced a new v2 MPU wrapper, namely + * mpu_wrappers_v2.c. Set configUSE_MPU_WRAPPERS_V1 to 0 to use the new v2 MPU + * wrapper. Set configUSE_MPU_WRAPPERS_V1 to 1 to use the old v1 MPU wrapper + * (mpu_wrappers.c). Defaults to 0 if left undefined. */ +#define configUSE_MPU_WRAPPERS_V1 0 + +/* When using the v2 MPU wrapper, set configPROTECTED_KERNEL_OBJECT_POOL_SIZE to + * the total number of kernel objects, which includes tasks, queues, semaphores, + * mutexes, event groups, timers, stream buffers and message buffers, in your + * application. The application will not be able to have more than + * configPROTECTED_KERNEL_OBJECT_POOL_SIZE kernel objects at any point of + * time. */ +#define configPROTECTED_KERNEL_OBJECT_POOL_SIZE 10 + +/* When using the v2 MPU wrapper, set configSYSTEM_CALL_STACK_SIZE to the size + * of the system call stack in words. Each task has a statically allocated + * memory buffer of this size which is used as the stack to execute system + * calls. For example, if configSYSTEM_CALL_STACK_SIZE is defined as 128 and + * there are 10 tasks in the application, the total amount of memory used for + * system call stacks is 128 * 10 = 1280 words. */ +#define configSYSTEM_CALL_STACK_SIZE 128 + +/* When using the v2 MPU wrapper, set configENABLE_ACCESS_CONTROL_LIST to 1 to + * enable Access Control List (ACL) feature. When ACL is enabled, an + * unprivileged task by default does not have access to any kernel object other + * than itself. The application writer needs to explicitly grant the + * unprivileged task access to the kernel objects it needs using the APIs + * provided for the same. Defaults to 0 if left undefined. */ +#define configENABLE_ACCESS_CONTROL_LIST 1 + +/******************************************************************************/ +/* SMP( Symmetric MultiProcessing ) Specific Configuration definitions. *******/ +/******************************************************************************/ + +/* Set configNUMBER_OF_CORES to the number of available processor cores. Defaults + * to 1 if left undefined. */ + +/* + #define configNUMBER_OF_CORES [Num of available cores] + */ + +/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set + * configRUN_MULTIPLE_PRIORITIES to 0 to allow multiple tasks to run + * simultaneously only if they do not have equal priority, thereby maintaining + * the paradigm of a lower priority task never running if a higher priority task + * is able to run. If configRUN_MULTIPLE_PRIORITIES is set to 1, multiple tasks + * with different priorities may run simultaneously - so a higher and lower + * priority task may run on different cores at the same time. */ +#define configRUN_MULTIPLE_PRIORITIES 0 + +/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set + * configUSE_CORE_AFFINITY to 1 to enable core affinity feature. When core + * affinity feature is enabled, the vTaskCoreAffinitySet and vTaskCoreAffinityGet + * APIs can be used to set and retrieve which cores a task can run on. If + * configUSE_CORE_AFFINITY is set to 0 then the FreeRTOS scheduler is free to + * run any task on any available core. */ +#define configUSE_CORE_AFFINITY 0 + +/* When using SMP with core affinity feature enabled, set + * configTASK_DEFAULT_CORE_AFFINITY to change the default core affinity mask for + * tasks created without an affinity mask specified. Setting the define to 1 would + * make such tasks run on core 0 and setting it to (1 << portGET_CORE_ID()) would + * make such tasks run on the current core. This config value is useful, if + * swapping tasks between cores is not supported (e.g. Tricore) or if legacy code + * should be controlled. Defaults to tskNO_AFFINITY if left undefined. */ +#define configTASK_DEFAULT_CORE_AFFINITY tskNO_AFFINITY + +/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), if + * configUSE_TASK_PREEMPTION_DISABLE is set to 1, individual tasks can be set to + * either pre-emptive or co-operative mode using the vTaskPreemptionDisable and + * vTaskPreemptionEnable APIs. */ +#define configUSE_TASK_PREEMPTION_DISABLE 0 + +/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set + * configUSE_PASSIVE_IDLE_HOOK to 1 to allow the application writer to use + * the passive idle task hook to add background functionality without the overhead + * of a separate task. Defaults to 0 if left undefined. */ +#define configUSE_PASSIVE_IDLE_HOOK 0 + +/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), + * configTIMER_SERVICE_TASK_CORE_AFFINITY allows the application writer to set + * the core affinity of the RTOS Daemon/Timer Service task. Defaults to + * tskNO_AFFINITY if left undefined. */ +#define configTIMER_SERVICE_TASK_CORE_AFFINITY tskNO_AFFINITY + + +/******************************************************************************/ +/* ARMv8-M secure side port related definitions. ******************************/ +/******************************************************************************/ + +/* secureconfigMAX_SECURE_CONTEXTS define the maximum number of tasks that can + * call into the secure side of an ARMv8-M chip. Not used by any other ports. */ +#define secureconfigMAX_SECURE_CONTEXTS 5 + +/* Defines the kernel provided implementation of + * vApplicationGetIdleTaskMemory() and vApplicationGetTimerTaskMemory() + * to provide the memory that is used by the Idle task and Timer task respectively. + * The application can provide it's own implementation of + * vApplicationGetIdleTaskMemory() and vApplicationGetTimerTaskMemory() by + * setting configKERNEL_PROVIDED_STATIC_MEMORY to 0 or leaving it undefined. */ +#define configKERNEL_PROVIDED_STATIC_MEMORY 1 + +/******************************************************************************/ +/* ARMv8-M port Specific Configuration definitions. ***************************/ +/******************************************************************************/ + +/* Set configENABLE_TRUSTZONE to 1 when running FreeRTOS on the non-secure side + * to enable the TrustZone support in FreeRTOS ARMv8-M ports which allows the + * non-secure FreeRTOS tasks to call the (non-secure callable) functions + * exported from secure side. */ +#define configENABLE_TRUSTZONE 1 + +/* If the application writer does not want to use TrustZone, but the hardware does + * not support disabling TrustZone then the entire application (including the FreeRTOS + * scheduler) can run on the secure side without ever branching to the non-secure side. + * To do that, in addition to setting configENABLE_TRUSTZONE to 0, also set + * configRUN_FREERTOS_SECURE_ONLY to 1. */ +#define configRUN_FREERTOS_SECURE_ONLY 1 + +/* Set configENABLE_MPU to 1 to enable the Memory Protection Unit (MPU), or 0 + * to leave the Memory Protection Unit disabled. */ +#define configENABLE_MPU 1 + +/* Set configENABLE_FPU to 1 to enable the Floating Point Unit (FPU), or 0 + * to leave the Floating Point Unit disabled. */ +#define configENABLE_FPU 1 + +/* Set configENABLE_MVE to 1 to enable the M-Profile Vector Extension (MVE) support, + * or 0 to leave the MVE support disabled. This option is only applicable to Cortex-M55 + * and Cortex-M85 ports as M-Profile Vector Extension (MVE) is available only on + * these architectures. configENABLE_MVE must be left undefined, or defined to 0 + * for the Cortex-M23,Cortex-M33 and Cortex-M35P ports. */ +#define configENABLE_MVE 1 + +/******************************************************************************/ +/* ARMv7-M and ARMv8-M port Specific Configuration definitions. ***************/ +/******************************************************************************/ + +/* Set configCHECK_HANDLER_INSTALLATION to 1 to enable additional asserts to verify + * that the application has correctly installed FreeRTOS interrupt handlers. + * + * An application can install FreeRTOS interrupt handlers in one of the following ways: + * 1. Direct Routing - Install the functions vPortSVCHandler and xPortPendSVHandler + * for SVC call and PendSV interrupts respectively. + * 2. Indirect Routing - Install separate handlers for SVC call and PendSV + * interrupts and route program control from those handlers + * to vPortSVCHandler and xPortPendSVHandler functions. + * The applications that use Indirect Routing must set configCHECK_HANDLER_INSTALLATION to 0. + * + * Defaults to 1 if left undefined. */ +#define configCHECK_HANDLER_INSTALLATION 1 + +/******************************************************************************/ +/* Definitions that include or exclude functionality. *************************/ +/******************************************************************************/ + +/* Set the following configUSE_* constants to 1 to include the named feature in + * the build, or 0 to exclude the named feature from the build. */ +#define configUSE_TASK_NOTIFICATIONS 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 0 +#define configUSE_APPLICATION_TASK_TAG 0 + +/* Set the following INCLUDE_* constants to 1 to incldue the named API function, + * or 0 to exclude the named API function. Most linkers will remove unused + * functions even when the constant is 1. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xResumeFromISR 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 0 +#define INCLUDE_xTaskAbortDelay 0 +#define INCLUDE_xTaskGetHandle 0 +#define INCLUDE_xTaskResumeFromISR 1 + +#endif /* FREERTOS_CONFIG_H */ From 62fb2b204b093f4bf4d666381af755d0e663fad7 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 21 Aug 2024 23:02:47 +0100 Subject: [PATCH 02/88] add demo freertos app --- freertos/app/CMakeLists.txt | 38 ++++++++++++++++++++++++--- freertos/app/TC-crush.cmake | 17 +++++++++++++ freertos/app/crush.ld | 38 +++++++++++++++++++++++++++ freertos/app/src/hal.c | 30 ++++++++++++++++++++++ freertos/app/src/hal.h | 8 ++++++ freertos/app/src/main.c | 51 +++++++++++++++++++++++++++++++++++++ freertos/app/src/start.S | 7 +++++ freertos/app/src/start.c | 40 +++++++++++++++++++++++++++++ 8 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 freertos/app/TC-crush.cmake create mode 100644 freertos/app/crush.ld create mode 100644 freertos/app/src/hal.c create mode 100644 freertos/app/src/hal.h create mode 100644 freertos/app/src/main.c create mode 100644 freertos/app/src/start.S create mode 100644 freertos/app/src/start.c diff --git a/freertos/app/CMakeLists.txt b/freertos/app/CMakeLists.txt index b83ad5f..5022e7c 100644 --- a/freertos/app/CMakeLists.txt +++ b/freertos/app/CMakeLists.txt @@ -1,6 +1,8 @@ -cmake_minimum_required(VERSION 3.12 FATAL_ERROR) +cmake_minimum_required(VERSION 3.15 FATAL_ERROR) -project(crush_freertos) +project(crush_freertos C ASM) + +set(CMAKE_C_STANDARD 11) include(FetchContent) @@ -11,12 +13,40 @@ FetchContent_Declare( freertos_kernel add_subdirectory(freertos_config) -set( FREERTOS_HEAP "4" CACHE STRING "" FORCE) +# no heap, only static allocation +# unset( FREERTOS_HEAP CACHE ) + # Select the native compile PORT set( FREERTOS_PORT "GCC_POSIX" CACHE STRING "" FORCE) + # Select the cross-compile PORT if (CMAKE_CROSSCOMPILING) - set(FREERTOS_PORT "GCC_ARM_CA9" CACHE STRING "" FORCE) + set(FREERTOS_RISCV_EXTENSION "RISCV_no_extensions" CACHE STRING "" FORCE) + set(FREERTOS_PORT "GCC_RISC_V_GENERIC" CACHE STRING "" FORCE) endif() FetchContent_MakeAvailable(freertos_kernel) + + +add_executable(${PROJECT_NAME} + src/main.c + src/hal.c + src/start.S + src/start.c +) + +target_link_options(${PROJECT_NAME} PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/crush.ld) +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/crush.ld) + +target_link_libraries(${PROJECT_NAME} PRIVATE freertos_kernel) + +string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) +find_program(objcopy_program ${objcopy_name} REQUIRED) +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${objcopy_program} -O binary ${PROJECT_NAME} ${PROJECT_NAME}.bin + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${objcopy_program} --verilog-data-width 4 -O verilog ${PROJECT_NAME} ${PROJECT_NAME}.data + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) diff --git a/freertos/app/TC-crush.cmake b/freertos/app/TC-crush.cmake new file mode 100644 index 0000000..2aa20a4 --- /dev/null +++ b/freertos/app/TC-crush.cmake @@ -0,0 +1,17 @@ +# https://www.vinnie.work/blog/2020-11-17-cmake-eval + +set(CMAKE_SYSTEM_NAME Generic) + +find_program(COMPILER_PATH + NAMES + # ubuntu and debian + riscv32-unknown-elf-gcc + riscv64-unknown-elf-gcc + # arch linux + riscv64-elf-gcc + REQUIRED) +get_filename_component(COMPILER_NAME ${COMPILER_PATH} NAME) +set(CMAKE_C_COMPILER ${COMPILER_NAME}) + +set(CMAKE_C_FLAGS "-nostartfiles -nostdlib -march=rv32i -mabi=ilp32") +set(CMAKE_ASM_FLAGS "-march=rv32i -mabi=ilp32") diff --git a/freertos/app/crush.ld b/freertos/app/crush.ld new file mode 100644 index 0000000..eec4140 --- /dev/null +++ b/freertos/app/crush.ld @@ -0,0 +1,38 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(start) + +MEMORY +{ + mem (rwx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 +} + +SECTIONS +{ + .mem : { + . = ALIGN(4); + KEEP(*(.start)) + *(.text .text.*) + *(.rodata .rodata*) + . = ALIGN(4); + *(.data .data.*); + } > mem + + .bss (NOLOAD) : { + . = ALIGN(4); + bss_start = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(4); + bss_end = .; + } > mem + + .stack : { + . = 1K; /* stack size */ + /* Calling conventions require 16 byte aligned stack pointer + * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + */ + . = ALIGN(16); + stack_start = .; + } > mem +} + diff --git a/freertos/app/src/hal.c b/freertos/app/src/hal.c new file mode 100644 index 0000000..b2269fc --- /dev/null +++ b/freertos/app/src/hal.c @@ -0,0 +1,30 @@ +#include "hal.h" +#include "FreeRTOS.h" +#include "task.h" + +void delay() +{ + vTaskDelay(pdMS_TO_TICKS(1000)); +} + +#define GPIO_BASE_ADDRESS ((int *)0x40000000) +#define BIT_MASK(n) (1 << (n)) + +bool get_button(void) +{ + volatile int *gpio = GPIO_BASE_ADDRESS; + return *gpio & BIT_MASK(8); +} + +void set_led_on(int index, bool led_on) +{ + volatile int *gpio = GPIO_BASE_ADDRESS; + if(led_on) + { + *gpio |= BIT_MASK(index); + } + else + { + *gpio &= ~BIT_MASK(index); + } +} diff --git a/freertos/app/src/hal.h b/freertos/app/src/hal.h new file mode 100644 index 0000000..1f989d2 --- /dev/null +++ b/freertos/app/src/hal.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +bool get_button(void); +void set_led_on(int index, bool led_on); + +void delay(); diff --git a/freertos/app/src/main.c b/freertos/app/src/main.c new file mode 100644 index 0000000..5894caf --- /dev/null +++ b/freertos/app/src/main.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "hal.h" + +static void task( void * parameters ); + +void main( void ) +{ + static StaticTask_t exampleTaskTCB; + static StackType_t exampleTaskStack[ configMINIMAL_STACK_SIZE ]; + + ( void ) printf( "Example FreeRTOS Project\n" ); + + ( void ) xTaskCreateStatic( task, + "example", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 1U, + &( exampleTaskStack[ 0 ] ), + &( exampleTaskTCB ) ); + + /* Start the scheduler. */ + vTaskStartScheduler(); + + for( ; ; ) + { + /* Should not reach here. */ + } +} + +void task(void *parameters) +{ + bool blinky_led_on = false; + for(;;) + { + blinky_led_on = !blinky_led_on; + + bool is_pressed = get_button(); + + set_led_on(0, blinky_led_on); + set_led_on(1, is_pressed); + delay(); + } +} diff --git a/freertos/app/src/start.S b/freertos/app/src/start.S new file mode 100644 index 0000000..b463235 --- /dev/null +++ b/freertos/app/src/start.S @@ -0,0 +1,7 @@ +.section .start +.global start +start: + // Load stack_start defined by the linker file to the stack pointer + la sp, stack_start + // Call c_start to do the rest of the initialisation + call c_start \ No newline at end of file diff --git a/freertos/app/src/start.c b/freertos/app/src/start.c new file mode 100644 index 0000000..8be6d5b --- /dev/null +++ b/freertos/app/src/start.c @@ -0,0 +1,40 @@ +/** + * \file Start-up code for hardware and C runtime initialisation. + */ + +/** + * \defgroup linker Symbols exported by the linker script + * @{ + */ + +/** The start of the region in RAM to be zero initialised */ +int bss_start[0]; +/** The end of the region in RAM to be zero initialised */ +int bss_end[0]; + +/** + * @} + */ + +int main(void); + +/** + * The entry point into the C application. + * + * It is called from assembly startup code in start.S, which is in turn placed + * at the initial PC using the linker script. + */ +void c_start(void) +{ + for(int *i = bss_start; i < bss_end; i++) + { + *i = 0; + } + + main(); + + // The assembly start code does not expect us to return, really main should + // not return either + for(;;) + ; +} From 2bb31537e049b7b6b21f9d1bb1aab80a3f1b3198 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 21 Aug 2024 23:30:28 +0100 Subject: [PATCH 03/88] fix obvious errors --- .../freertos_config/include/FreeRTOSConfig.h | 3 + freertos/app/freertos_config/include/stdint.h | 62 +++++++++++++++++++ freertos/app/freertos_config/include/string.h | 5 ++ 3 files changed, 70 insertions(+) create mode 100644 freertos/app/freertos_config/include/stdint.h create mode 100644 freertos/app/freertos_config/include/string.h diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h index 33f80ea..955eca3 100644 --- a/freertos/app/freertos_config/include/FreeRTOSConfig.h +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -645,4 +645,7 @@ #define INCLUDE_xTaskGetHandle 0 #define INCLUDE_xTaskResumeFromISR 1 +#define configMTIME_BASE_ADDRESS 0 +#define configMTIMECMP_BASE_ADDRESS 0 + #endif /* FREERTOS_CONFIG_H */ diff --git a/freertos/app/freertos_config/include/stdint.h b/freertos/app/freertos_config/include/stdint.h new file mode 100644 index 0000000..1c51916 --- /dev/null +++ b/freertos/app/freertos_config/include/stdint.h @@ -0,0 +1,62 @@ +/* + * FreeRTOS Kernel V11.1.0 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef FREERTOS_STDINT +#define FREERTOS_STDINT + +/******************************************************************************* + * THIS IS NOT A FULL stdint.h IMPLEMENTATION - It only contains the definitions + * necessary to build the FreeRTOS code. It is provided to allow FreeRTOS to be + * built using compilers that do not provide their own stdint.h definition. + * + * To use this file: + * + * 1) Copy this file into the directory that contains your FreeRTOSConfig.h + * header file, as that directory will already be in the compiler's include + * path. + * + * 2) Rename the copied file stdint.h. + * + */ + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef long int32_t; +typedef unsigned long uint32_t; + +#ifdef __UINT64_TYPE__ +typedef __UINT64_TYPE__ uint64_t; +#endif + +#ifndef SIZE_MAX + #define SIZE_MAX ( ( size_t ) -1 ) +#endif + +#endif /* FREERTOS_STDINT */ diff --git a/freertos/app/freertos_config/include/string.h b/freertos/app/freertos_config/include/string.h new file mode 100644 index 0000000..29a422d --- /dev/null +++ b/freertos/app/freertos_config/include/string.h @@ -0,0 +1,5 @@ +#pragma once + +/* The FreeRTOS GCC RISC-V port depends on some functions from string.h. We + * don't use a stdlib, so must manually implement the functions that are used. + */ From 253e9555fd88487ef4d571d801124e748de857b7 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sat, 24 Aug 2024 20:49:19 +0100 Subject: [PATCH 04/88] WIP settings up build --- freertos/app/TC-crush.cmake | 4 +- freertos/app/freertos_config/include/stdint.h | 80 ++++++------------- freertos/app/freertos_config/include/stdlib.h | 0 freertos/app/freertos_config/include/string.h | 5 ++ freertos/app/src/main.c | 3 - 5 files changed, 30 insertions(+), 62 deletions(-) create mode 100644 freertos/app/freertos_config/include/stdlib.h diff --git a/freertos/app/TC-crush.cmake b/freertos/app/TC-crush.cmake index 2aa20a4..ac22b3a 100644 --- a/freertos/app/TC-crush.cmake +++ b/freertos/app/TC-crush.cmake @@ -13,5 +13,5 @@ find_program(COMPILER_PATH get_filename_component(COMPILER_NAME ${COMPILER_PATH} NAME) set(CMAKE_C_COMPILER ${COMPILER_NAME}) -set(CMAKE_C_FLAGS "-nostartfiles -nostdlib -march=rv32i -mabi=ilp32") -set(CMAKE_ASM_FLAGS "-march=rv32i -mabi=ilp32") +set(CMAKE_C_FLAGS "-nostartfiles -nostdlib -march=rv32i_zicsr -mabi=ilp32") +set(CMAKE_ASM_FLAGS "-march=rv32i_zicsr -mabi=ilp32") diff --git a/freertos/app/freertos_config/include/stdint.h b/freertos/app/freertos_config/include/stdint.h index 1c51916..8133e2f 100644 --- a/freertos/app/freertos_config/include/stdint.h +++ b/freertos/app/freertos_config/include/stdint.h @@ -1,62 +1,28 @@ -/* - * FreeRTOS Kernel V11.1.0 - * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * https://www.FreeRTOS.org - * https://github.com/FreeRTOS - * - */ - -#ifndef FREERTOS_STDINT -#define FREERTOS_STDINT - -/******************************************************************************* - * THIS IS NOT A FULL stdint.h IMPLEMENTATION - It only contains the definitions - * necessary to build the FreeRTOS code. It is provided to allow FreeRTOS to be - * built using compilers that do not provide their own stdint.h definition. - * - * To use this file: - * - * 1) Copy this file into the directory that contains your FreeRTOSConfig.h - * header file, as that directory will already be in the compiler's include - * path. - * - * 2) Rename the copied file stdint.h. - * - */ - -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef long int32_t; -typedef unsigned long uint32_t; +#pragma once +#ifdef __INT8_TYPE__ +typedef __INT8_TYPE__ int8_t; +#endif +#ifdef __INT16_TYPE__ +typedef __INT16_TYPE__ int16_t; +#endif +#ifdef __INT32_TYPE__ +typedef __INT32_TYPE__ int32_t; +#endif +#ifdef __INT64_TYPE__ +typedef __INT64_TYPE__ int64_t; +#endif +#ifdef __UINT8_TYPE__ +typedef __UINT8_TYPE__ uint8_t; +#endif +#ifdef __UINT16_TYPE__ +typedef __UINT16_TYPE__ uint16_t; +#endif +#ifdef __UINT32_TYPE__ +typedef __UINT32_TYPE__ uint32_t; +#endif #ifdef __UINT64_TYPE__ typedef __UINT64_TYPE__ uint64_t; #endif -#ifndef SIZE_MAX - #define SIZE_MAX ( ( size_t ) -1 ) -#endif - -#endif /* FREERTOS_STDINT */ +#define SIZE_MAX __SIZE_MAX__ diff --git a/freertos/app/freertos_config/include/stdlib.h b/freertos/app/freertos_config/include/stdlib.h new file mode 100644 index 0000000..e69de29 diff --git a/freertos/app/freertos_config/include/string.h b/freertos/app/freertos_config/include/string.h index 29a422d..d1eacbb 100644 --- a/freertos/app/freertos_config/include/string.h +++ b/freertos/app/freertos_config/include/string.h @@ -1,5 +1,10 @@ #pragma once +#include + /* The FreeRTOS GCC RISC-V port depends on some functions from string.h. We * don't use a stdlib, so must manually implement the functions that are used. */ + +void* memcpy( void *restrict dest, const void *restrict src, size_t count ); +void *memset( void *dest, int ch, size_t count ); diff --git a/freertos/app/src/main.c b/freertos/app/src/main.c index 5894caf..844bb78 100644 --- a/freertos/app/src/main.c +++ b/freertos/app/src/main.c @@ -5,7 +5,6 @@ #include #include -#include #include "hal.h" @@ -16,8 +15,6 @@ void main( void ) static StaticTask_t exampleTaskTCB; static StackType_t exampleTaskStack[ configMINIMAL_STACK_SIZE ]; - ( void ) printf( "Example FreeRTOS Project\n" ); - ( void ) xTaskCreateStatic( task, "example", configMINIMAL_STACK_SIZE, From ab3f6f430ba8b408226b07bcddde67b6888de2c1 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sat, 24 Aug 2024 21:28:09 +0100 Subject: [PATCH 05/88] WIP --- freertos/app/CMakeLists.txt | 3 + freertos/app/freertos_config/CMakeLists.txt | 19 +++--- .../freertos_config/include/FreeRTOSConfig.h | 2 +- freertos/app/freertos_config/string.c | 64 +++++++++++++++++++ 4 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 freertos/app/freertos_config/string.c diff --git a/freertos/app/CMakeLists.txt b/freertos/app/CMakeLists.txt index 5022e7c..5b8d80b 100644 --- a/freertos/app/CMakeLists.txt +++ b/freertos/app/CMakeLists.txt @@ -40,6 +40,9 @@ set_target_properties(${PROJECT_NAME} PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SO target_link_libraries(${PROJECT_NAME} PRIVATE freertos_kernel) +# Since we use -nostdlib, we must link to libgcc manually +target_link_libraries(${PROJECT_NAME} PRIVATE gcc) + string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) find_program(objcopy_program ${objcopy_name} REQUIRED) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD diff --git a/freertos/app/freertos_config/CMakeLists.txt b/freertos/app/freertos_config/CMakeLists.txt index c94d2ad..4f5900c 100644 --- a/freertos/app/freertos_config/CMakeLists.txt +++ b/freertos/app/freertos_config/CMakeLists.txt @@ -1,15 +1,12 @@ -add_library(freertos_config INTERFACE) +add_library(freertos_config STATIC) -target_include_directories(freertos_config SYSTEM -INTERFACE - include -) +target_include_directories(freertos_config SYSTEM INTERFACE include) +target_include_directories(freertos_config PRIVATE include) -target_compile_definitions(freertos_config - INTERFACE - projCOVERAGE_TEST=0 -) +target_compile_definitions(freertos_config PUBLIC projCOVERAGE_TEST=0) + +target_sources(freertos_config PRIVATE string.c) # options for cross-compilation or something like that? -target_compile_definitions(freertos_config INTERFACE ${definitions}) -target_compile_options(freertos_config INTERFACE ${options}) +target_compile_definitions(freertos_config PUBLIC ${definitions}) +target_compile_options(freertos_config PUBLIC ${options}) diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h index 955eca3..f8df04c 100644 --- a/freertos/app/freertos_config/include/FreeRTOSConfig.h +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -274,7 +274,7 @@ * memory in the build. Set to 0 to exclude the ability to create dynamically * allocated objects from the build. Defaults to 1 if left undefined. See * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */ -#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 /* Sets the total size of the FreeRTOS heap, in bytes, when heap_1.c, heap_2.c * or heap_4.c are included in the build. This value is defaulted to 4096 bytes but diff --git a/freertos/app/freertos_config/string.c b/freertos/app/freertos_config/string.c new file mode 100644 index 0000000..ea989d6 --- /dev/null +++ b/freertos/app/freertos_config/string.c @@ -0,0 +1,64 @@ +#pragma once + +#include + +/* When using -nostdlib with GCC, it may still generate calls to memcmp, + * memset, memcpy and memmove. These usually come from the standard C library, + * but we don't have one. Define the functions here so that the app can still + * link. + * + * memcpy and memset are also used by FreeRTOS implementation. + */ + +void* memcpy( void *restrict a_dest, const void *restrict a_src, size_t count ) { + char *dest = a_dest; + const char *src = a_src; + + for(int i = 0; i < count; i++) { + dest[i] = src[i]; + } +} + +void *memset( void *a_dest, int ch, size_t count ) { + char *dest = a_dest; + + for(int i = 0; i < count; i++) { + dest[i] = ch; + } +} + +int memcmp( const void* a_lhs, const void* a_rhs, size_t count ) { + const unsigned char *lhs = a_lhs; + const unsigned char *rhs = a_rhs; + + for(int i = 0; i < count; i++) { + const unsigned char l = lhs[i]; + const unsigned char r = rhs[i]; + + if(l != r) + { + return (int)l - (int)r; + } + } + + return 0; +} + +void *memmove(void *a_dest, const void *a_src, size_t count) { + unsigned char *dest = a_dest; + const unsigned char *src = a_src; + + if (dest == src || count == 0) { + // nothing to copy + } else if (dest < src) { + for (size_t i = 0; i < count; i++) { + dest[i] = src[i]; + } + } else { + for (size_t i = count; i > 0; i--) { + dest[i - 1] = src[i - 1]; + } + } + + return a_dest; +} From eebd0d3524512b191cc747f1f52548f3acb4de78 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sat, 24 Aug 2024 21:52:16 +0100 Subject: [PATCH 06/88] Update config --- .../freertos_config/include/FreeRTOSConfig.h | 245 ++---------------- 1 file changed, 16 insertions(+), 229 deletions(-) diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h index f8df04c..5b68831 100644 --- a/freertos/app/freertos_config/include/FreeRTOSConfig.h +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -53,22 +53,6 @@ * This is very often, but not always, equal to the main system clock frequency. */ #define configCPU_CLOCK_HZ ( ( unsigned long ) 20000000 ) -/* configSYSTICK_CLOCK_HZ is an optional parameter for ARM Cortex-M ports only. - * - * By default ARM Cortex-M ports generate the RTOS tick interrupt from the - * Cortex-M SysTick timer. Most Cortex-M MCUs run the SysTick timer at the same - * frequency as the MCU itself - when that is the case configSYSTICK_CLOCK_HZ is - * not needed and should be left undefined. If the SysTick timer is clocked at a - * different frequency to the MCU core then set configCPU_CLOCK_HZ to the MCU clock - * frequency, as normal, and configSYSTICK_CLOCK_HZ to the SysTick clock - * frequency. Not used if left undefined. - * The default value is undefined (commented out). If you need this value bring it - * back and set it to a suitable value. */ - -/* - #define configSYSTICK_CLOCK_HZ [Platform specific] - */ - /******************************************************************************/ /* Scheduling behaviour related definitions. **********************************/ /******************************************************************************/ @@ -245,7 +229,7 @@ * FreeRTOS/source/event_groups.c source file must be included in the build if * configUSE_EVENT_GROUPS is set to 1. Defaults to 1 if left undefined. */ -#define configUSE_EVENT_GROUPS 1 +#define configUSE_EVENT_GROUPS 0 /******************************************************************************/ /* Stream Buffer related definitions. *****************************************/ @@ -256,7 +240,7 @@ * FreeRTOS/source/stream_buffer.c source file must be included in the build if * configUSE_STREAM_BUFFERS is set to 1. Defaults to 1 if left undefined. */ -#define configUSE_STREAM_BUFFERS 1 +#define configUSE_STREAM_BUFFERS 0 /******************************************************************************/ /* Memory allocation related definitions. *************************************/ @@ -354,7 +338,7 @@ * the stack overflow callback when configCHECK_FOR_STACK_OVERFLOW is set to 1. * See https://www.freertos.org/Stacks-and-stack-overflow-checking.html Defaults * to 0 if left undefined. */ -#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_FOR_STACK_OVERFLOW 0 /******************************************************************************/ /* Run time and task stats gathering related definitions. *********************/ @@ -414,203 +398,6 @@ ; \ } -/******************************************************************************/ -/* FreeRTOS MPU specific definitions. *****************************************/ -/******************************************************************************/ - -/* If configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS is set to 1 then - * the application writer can provide functions that execute in privileged mode. - * See: https://www.freertos.org/a00110.html#configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS - * Defaults to 0 if left undefined. Only used by the FreeRTOS Cortex-M MPU ports, - * not the standard ARMv7-M Cortex-M port. */ -#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 - -/* Set configTOTAL_MPU_REGIONS to the number of MPU regions implemented on your - * target hardware. Normally 8 or 16. Only used by the FreeRTOS Cortex-M MPU - * ports, not the standard ARMv7-M Cortex-M port. Defaults to 8 if left - * undefined. */ -#define configTOTAL_MPU_REGIONS 8 - -/* configTEX_S_C_B_FLASH allows application writers to override the default - * values for the for TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for - * the MPU region covering Flash. Defaults to 0x07UL (which means TEX=000, S=1, - * C=1, B=1) if left undefined. Only used by the FreeRTOS Cortex-M MPU ports, not - * the standard ARMv7-M Cortex-M port. */ -#define configTEX_S_C_B_FLASH 0x07UL - -/* configTEX_S_C_B_SRAM allows application writers to override the default - * values for the for TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for - * the MPU region covering RAM. Defaults to 0x07UL (which means TEX=000, S=1, C=1, - * B=1) if left undefined. Only used by the FreeRTOS Cortex-M MPU ports, not - * the standard ARMv7-M Cortex-M port. */ -#define configTEX_S_C_B_SRAM 0x07UL - -/* Set configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY to 0 to prevent any privilege - * escalations originating from outside of the kernel code itself. Set to 1 to - * allow application tasks to raise privilege. Defaults to 1 if left undefined. - * Only used by the FreeRTOS Cortex-M MPU ports, not the standard ARMv7-M Cortex-M - * port. */ -#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1 - -/* Set configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS to 1 to allow unprivileged - * tasks enter critical sections (effectively mask interrupts). Set to 0 to - * prevent unprivileged tasks entering critical sections. Defaults to 1 if left - * undefined. Only used by the FreeRTOS Cortex-M MPU ports, not the standard - * ARMv7-M Cortex-M port. */ -#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 0 - -/* FreeRTOS Kernel version 10.6.0 introduced a new v2 MPU wrapper, namely - * mpu_wrappers_v2.c. Set configUSE_MPU_WRAPPERS_V1 to 0 to use the new v2 MPU - * wrapper. Set configUSE_MPU_WRAPPERS_V1 to 1 to use the old v1 MPU wrapper - * (mpu_wrappers.c). Defaults to 0 if left undefined. */ -#define configUSE_MPU_WRAPPERS_V1 0 - -/* When using the v2 MPU wrapper, set configPROTECTED_KERNEL_OBJECT_POOL_SIZE to - * the total number of kernel objects, which includes tasks, queues, semaphores, - * mutexes, event groups, timers, stream buffers and message buffers, in your - * application. The application will not be able to have more than - * configPROTECTED_KERNEL_OBJECT_POOL_SIZE kernel objects at any point of - * time. */ -#define configPROTECTED_KERNEL_OBJECT_POOL_SIZE 10 - -/* When using the v2 MPU wrapper, set configSYSTEM_CALL_STACK_SIZE to the size - * of the system call stack in words. Each task has a statically allocated - * memory buffer of this size which is used as the stack to execute system - * calls. For example, if configSYSTEM_CALL_STACK_SIZE is defined as 128 and - * there are 10 tasks in the application, the total amount of memory used for - * system call stacks is 128 * 10 = 1280 words. */ -#define configSYSTEM_CALL_STACK_SIZE 128 - -/* When using the v2 MPU wrapper, set configENABLE_ACCESS_CONTROL_LIST to 1 to - * enable Access Control List (ACL) feature. When ACL is enabled, an - * unprivileged task by default does not have access to any kernel object other - * than itself. The application writer needs to explicitly grant the - * unprivileged task access to the kernel objects it needs using the APIs - * provided for the same. Defaults to 0 if left undefined. */ -#define configENABLE_ACCESS_CONTROL_LIST 1 - -/******************************************************************************/ -/* SMP( Symmetric MultiProcessing ) Specific Configuration definitions. *******/ -/******************************************************************************/ - -/* Set configNUMBER_OF_CORES to the number of available processor cores. Defaults - * to 1 if left undefined. */ - -/* - #define configNUMBER_OF_CORES [Num of available cores] - */ - -/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set - * configRUN_MULTIPLE_PRIORITIES to 0 to allow multiple tasks to run - * simultaneously only if they do not have equal priority, thereby maintaining - * the paradigm of a lower priority task never running if a higher priority task - * is able to run. If configRUN_MULTIPLE_PRIORITIES is set to 1, multiple tasks - * with different priorities may run simultaneously - so a higher and lower - * priority task may run on different cores at the same time. */ -#define configRUN_MULTIPLE_PRIORITIES 0 - -/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set - * configUSE_CORE_AFFINITY to 1 to enable core affinity feature. When core - * affinity feature is enabled, the vTaskCoreAffinitySet and vTaskCoreAffinityGet - * APIs can be used to set and retrieve which cores a task can run on. If - * configUSE_CORE_AFFINITY is set to 0 then the FreeRTOS scheduler is free to - * run any task on any available core. */ -#define configUSE_CORE_AFFINITY 0 - -/* When using SMP with core affinity feature enabled, set - * configTASK_DEFAULT_CORE_AFFINITY to change the default core affinity mask for - * tasks created without an affinity mask specified. Setting the define to 1 would - * make such tasks run on core 0 and setting it to (1 << portGET_CORE_ID()) would - * make such tasks run on the current core. This config value is useful, if - * swapping tasks between cores is not supported (e.g. Tricore) or if legacy code - * should be controlled. Defaults to tskNO_AFFINITY if left undefined. */ -#define configTASK_DEFAULT_CORE_AFFINITY tskNO_AFFINITY - -/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), if - * configUSE_TASK_PREEMPTION_DISABLE is set to 1, individual tasks can be set to - * either pre-emptive or co-operative mode using the vTaskPreemptionDisable and - * vTaskPreemptionEnable APIs. */ -#define configUSE_TASK_PREEMPTION_DISABLE 0 - -/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), set - * configUSE_PASSIVE_IDLE_HOOK to 1 to allow the application writer to use - * the passive idle task hook to add background functionality without the overhead - * of a separate task. Defaults to 0 if left undefined. */ -#define configUSE_PASSIVE_IDLE_HOOK 0 - -/* When using SMP (i.e. configNUMBER_OF_CORES is greater than one), - * configTIMER_SERVICE_TASK_CORE_AFFINITY allows the application writer to set - * the core affinity of the RTOS Daemon/Timer Service task. Defaults to - * tskNO_AFFINITY if left undefined. */ -#define configTIMER_SERVICE_TASK_CORE_AFFINITY tskNO_AFFINITY - - -/******************************************************************************/ -/* ARMv8-M secure side port related definitions. ******************************/ -/******************************************************************************/ - -/* secureconfigMAX_SECURE_CONTEXTS define the maximum number of tasks that can - * call into the secure side of an ARMv8-M chip. Not used by any other ports. */ -#define secureconfigMAX_SECURE_CONTEXTS 5 - -/* Defines the kernel provided implementation of - * vApplicationGetIdleTaskMemory() and vApplicationGetTimerTaskMemory() - * to provide the memory that is used by the Idle task and Timer task respectively. - * The application can provide it's own implementation of - * vApplicationGetIdleTaskMemory() and vApplicationGetTimerTaskMemory() by - * setting configKERNEL_PROVIDED_STATIC_MEMORY to 0 or leaving it undefined. */ -#define configKERNEL_PROVIDED_STATIC_MEMORY 1 - -/******************************************************************************/ -/* ARMv8-M port Specific Configuration definitions. ***************************/ -/******************************************************************************/ - -/* Set configENABLE_TRUSTZONE to 1 when running FreeRTOS on the non-secure side - * to enable the TrustZone support in FreeRTOS ARMv8-M ports which allows the - * non-secure FreeRTOS tasks to call the (non-secure callable) functions - * exported from secure side. */ -#define configENABLE_TRUSTZONE 1 - -/* If the application writer does not want to use TrustZone, but the hardware does - * not support disabling TrustZone then the entire application (including the FreeRTOS - * scheduler) can run on the secure side without ever branching to the non-secure side. - * To do that, in addition to setting configENABLE_TRUSTZONE to 0, also set - * configRUN_FREERTOS_SECURE_ONLY to 1. */ -#define configRUN_FREERTOS_SECURE_ONLY 1 - -/* Set configENABLE_MPU to 1 to enable the Memory Protection Unit (MPU), or 0 - * to leave the Memory Protection Unit disabled. */ -#define configENABLE_MPU 1 - -/* Set configENABLE_FPU to 1 to enable the Floating Point Unit (FPU), or 0 - * to leave the Floating Point Unit disabled. */ -#define configENABLE_FPU 1 - -/* Set configENABLE_MVE to 1 to enable the M-Profile Vector Extension (MVE) support, - * or 0 to leave the MVE support disabled. This option is only applicable to Cortex-M55 - * and Cortex-M85 ports as M-Profile Vector Extension (MVE) is available only on - * these architectures. configENABLE_MVE must be left undefined, or defined to 0 - * for the Cortex-M23,Cortex-M33 and Cortex-M35P ports. */ -#define configENABLE_MVE 1 - -/******************************************************************************/ -/* ARMv7-M and ARMv8-M port Specific Configuration definitions. ***************/ -/******************************************************************************/ - -/* Set configCHECK_HANDLER_INSTALLATION to 1 to enable additional asserts to verify - * that the application has correctly installed FreeRTOS interrupt handlers. - * - * An application can install FreeRTOS interrupt handlers in one of the following ways: - * 1. Direct Routing - Install the functions vPortSVCHandler and xPortPendSVHandler - * for SVC call and PendSV interrupts respectively. - * 2. Indirect Routing - Install separate handlers for SVC call and PendSV - * interrupts and route program control from those handlers - * to vPortSVCHandler and xPortPendSVHandler functions. - * The applications that use Indirect Routing must set configCHECK_HANDLER_INSTALLATION to 0. - * - * Defaults to 1 if left undefined. */ -#define configCHECK_HANDLER_INSTALLATION 1 - /******************************************************************************/ /* Definitions that include or exclude functionality. *************************/ /******************************************************************************/ @@ -619,31 +406,31 @@ * the build, or 0 to exclude the named feature from the build. */ #define configUSE_TASK_NOTIFICATIONS 1 #define configUSE_MUTEXES 1 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_RECURSIVE_MUTEXES 0 +#define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_QUEUE_SETS 0 #define configUSE_APPLICATION_TASK_TAG 0 /* Set the following INCLUDE_* constants to 1 to incldue the named API function, * or 0 to exclude the named API function. Most linkers will remove unused * functions even when the constant is 1. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_xResumeFromISR 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTaskGetSchedulerState 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 0 +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 0 +#define INCLUDE_vTaskDelay 0 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 0 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 -#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xEventGroupSetBitFromISR 0 #define INCLUDE_xTimerPendFunctionCall 0 #define INCLUDE_xTaskAbortDelay 0 #define INCLUDE_xTaskGetHandle 0 -#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xTaskResumeFromISR 0 #define configMTIME_BASE_ADDRESS 0 #define configMTIMECMP_BASE_ADDRESS 0 From 4593739dc43a7625e73c02c2b45f7526970965f0 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sun, 25 Aug 2024 11:16:51 +0100 Subject: [PATCH 07/88] fix build for the most part --- freertos/app/freertos_config/include/FreeRTOSConfig.h | 7 +++++-- freertos/app/freertos_config/string.c | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h index 5b68831..c2cc05d 100644 --- a/freertos/app/freertos_config/include/FreeRTOSConfig.h +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -252,6 +252,7 @@ * allocated objects from the build. Defaults to 0 if left undefined. See * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */ #define configSUPPORT_STATIC_ALLOCATION 1 +#define configKERNEL_PROVIDED_STATIC_MEMORY 1 /* Set configSUPPORT_DYNAMIC_ALLOCATION to 1 to include FreeRTOS API functions * that create FreeRTOS objects (tasks, queues, etc.) using dynamically allocated @@ -420,9 +421,11 @@ #define INCLUDE_vTaskSuspend 0 #define INCLUDE_xResumeFromISR 0 #define INCLUDE_vTaskDelayUntil 0 -#define INCLUDE_vTaskDelay 0 +#define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 0 -#define INCLUDE_xTaskGetCurrentTaskHandle 0 +// Must be on for the FreeRTOS bunded CMake script to work, as it always adds +// stream_buffers.c, and that file requires this to be on. +#define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 diff --git a/freertos/app/freertos_config/string.c b/freertos/app/freertos_config/string.c index ea989d6..7b7b6b5 100644 --- a/freertos/app/freertos_config/string.c +++ b/freertos/app/freertos_config/string.c @@ -1,5 +1,3 @@ -#pragma once - #include /* When using -nostdlib with GCC, it may still generate calls to memcmp, From 583b131b76b34fc18ccfdea2470259716e33e1d0 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sun, 25 Aug 2024 11:36:17 +0100 Subject: [PATCH 08/88] set up IRQ stack --- freertos/app/crush.ld | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/freertos/app/crush.ld b/freertos/app/crush.ld index eec4140..c9ac79e 100644 --- a/freertos/app/crush.ld +++ b/freertos/app/crush.ld @@ -3,19 +3,31 @@ ENTRY(start) MEMORY { - mem (rwx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 + ram (rwx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 + + /* TODO move firmware to the flash, set up load from flash to program memory */ + /* + * TODO would be even better if we move the RAM to SPRAM too next to the + * firmware and stop using blockram. + */ + /* + ram (rw): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 + program (rx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 + flash (r): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 + */ } SECTIONS { - .mem : { + /* TODO move firmware to the program memory, set up load from flash to program memory */ + .ram : { . = ALIGN(4); KEEP(*(.start)) *(.text .text.*) *(.rodata .rodata*) . = ALIGN(4); *(.data .data.*); - } > mem + } > ram .bss (NOLOAD) : { . = ALIGN(4); @@ -24,15 +36,18 @@ SECTIONS *(COMMON) . = ALIGN(4); bss_end = .; - } > mem + } > ram - .stack : { + /* Calling conventions require 16 byte aligned stack pointer + * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + * + * This is initially the entry point stack, then is reused as the FreeRTOS + * interrupt stack when the scheduler starts. + */ + .stack : ALIGN(16) { . = 1K; /* stack size */ - /* Calling conventions require 16 byte aligned stack pointer - * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc - */ - . = ALIGN(16); stack_start = .; - } > mem + __freertos_irq_stack_top = .; + } > ram } From 5abb95e9c150a15ff2b17dfd7322ef6cd72b39d2 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sun, 25 Aug 2024 14:01:25 +0100 Subject: [PATCH 09/88] add TODO for setting up interrupts --- freertos/app/src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freertos/app/src/main.c b/freertos/app/src/main.c index 844bb78..125aa5c 100644 --- a/freertos/app/src/main.c +++ b/freertos/app/src/main.c @@ -14,6 +14,8 @@ void main( void ) { static StaticTask_t exampleTaskTCB; static StackType_t exampleTaskStack[ configMINIMAL_STACK_SIZE ]; + + // TODO: install freertos_risc_v_trap_handler as the interrupt handler ( void ) xTaskCreateStatic( task, "example", From 83c6aa727b11ea166af10a1f96d35e32201a07a2 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sun, 25 Aug 2024 18:23:35 +0100 Subject: [PATCH 10/88] Configure FreeRTOS to use mtime, mtimecmp for system tick --- freertos/app/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/freertos/app/CMakeLists.txt b/freertos/app/CMakeLists.txt index 5b8d80b..fe3cfad 100644 --- a/freertos/app/CMakeLists.txt +++ b/freertos/app/CMakeLists.txt @@ -21,7 +21,10 @@ set( FREERTOS_PORT "GCC_POSIX" CACHE STRING "" FORCE) # Select the cross-compile PORT if (CMAKE_CROSSCOMPILING) - set(FREERTOS_RISCV_EXTENSION "RISCV_no_extensions" CACHE STRING "" FORCE) + # We don't have a sifive CLINT, but that define seems to be unused anyway, + # and the MTIME define is required for FreeRTOS to automatically use the + # mtime for system tick. + set(FREERTOS_RISCV_EXTENSION "RISCV_MTIME_CLINT_no_extensions" CACHE STRING "" FORCE) set(FREERTOS_PORT "GCC_RISC_V_GENERIC" CACHE STRING "" FORCE) endif() From 35db7648aaca1966a13624265a8551e612f33714 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sun, 25 Aug 2024 18:33:42 +0100 Subject: [PATCH 11/88] Update python dependencies for Python 3.12 support --- requirements.txt | 73 +++++++++++++++++------------------------------- 1 file changed, 26 insertions(+), 47 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7b32bfc..857a2bd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,11 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # # pip-compile # -attrs==23.1.0 - # via - # jsonschema - # okonomiyaki - # referencing - # simplesat +attrs==24.2.0 + # via simplesat cerberus==1.3.5 # via riscv-config chardet==5.2.0 @@ -18,21 +14,19 @@ click==8.1.7 # via # riscof # riscv-isac -colorlog==6.7.0 +colorlog==6.8.2 # via riscv-isac dataproperty==1.0.1 # via # pytablewriter # tabledata -distro==1.8.0 - # via okonomiyaki -edalize==0.5.1 +edalize==0.5.4 # via fusesoc -fastjsonschema==2.18.0 +fastjsonschema==2.20.0 # via fusesoc fusesoc==2.2.1 # via -r requirements.in -gitdb==4.0.10 +gitdb==4.0.11 # via gitpython gitpython==3.1.17 # via @@ -40,90 +34,75 @@ gitpython==3.1.17 # riscv-isac iniconfig==2.0.0 # via pytest -jinja2==3.1.2 +jinja2==3.1.4 # via # edalize # riscof -jsonschema==4.19.0 - # via okonomiyaki -jsonschema-specifications==2023.7.1 - # via jsonschema -markupsafe==2.1.3 +markupsafe==2.1.5 # via jinja2 mbstrdecoder==1.1.3 # via # dataproperty # pytablewriter # typepy -okonomiyaki==1.4.0 +okonomiyaki==2.0.0 # via simplesat -packaging==23.1 +packaging==24.1 # via # pytest # typepy -pathvalidate==3.1.0 +pathvalidate==3.2.1 # via pytablewriter -pluggy==1.3.0 +pluggy==1.5.0 # via pytest pyelftools==0.26 # via riscv-isac -pyparsing==3.1.1 +pyparsing==3.1.4 # via fusesoc -pytablewriter==1.0.0 +pytablewriter==1.2.0 # via riscv-isac -pytest==7.4.1 +pytest==8.3.2 # via riscv-isac -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via typepy -pytz==2023.3 +pytz==2024.1 # via # riscof # typepy -pyyaml==6.0.1 +pyyaml==5.2 # via # fusesoc # riscv-config # riscv-isac -referencing==0.30.2 - # via - # jsonschema - # jsonschema-specifications riscof==1.25.3 # via -r requirements.in -riscv-config==3.7.2 +riscv-config==3.18.3 # via riscof riscv-isac==0.18.0 # via riscof -rpds-py==0.10.2 - # via - # jsonschema - # referencing -ruamel-yaml==0.17.32 +ruamel-yaml==0.18.6 # via # riscv-config # riscv-isac -ruamel-yaml-clib==0.2.7 +ruamel-yaml-clib==0.2.8 # via ruamel-yaml simplesat==0.8.2 # via fusesoc six==1.16.0 # via - # okonomiyaki # python-dateutil # simplesat -smmap==5.0.0 +smmap==5.0.1 # via gitdb -tabledata==1.3.1 +tabledata==1.3.3 # via pytablewriter -tcolorpy==0.1.3 +tcolorpy==0.1.6 # via pytablewriter -typepy[datetime]==1.3.1 +typepy[datetime]==1.3.2 # via # dataproperty # pytablewriter # tabledata -zipfile2==0.0.12 - # via okonomiyaki # The following packages are considered to be unsafe in a requirements file: # setuptools From 14c456b1565166232f06d3f8471a75e6f7d20d2d Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sun, 25 Aug 2024 21:11:09 +0100 Subject: [PATCH 12/88] Update to latest riscv-arch-test --- tools/compliance/config.ini | 2 +- tools/compliance/riscv-arch-test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/compliance/config.ini b/tools/compliance/config.ini index 1e72787..3fd26c6 100644 --- a/tools/compliance/config.ini +++ b/tools/compliance/config.ini @@ -8,7 +8,7 @@ DUTPluginPath=crush pluginpath=crush ispec=crush/crush_isa.yaml pspec=crush/crush_platform.yaml -compiler_name_prefix=riscv32-unknown-elf +compiler_name_prefix=riscv64-elf [sail_cSim] pluginpath=riscof-plugins/sail_cSim diff --git a/tools/compliance/riscv-arch-test b/tools/compliance/riscv-arch-test index 46cf99d..9c65b8c 160000 --- a/tools/compliance/riscv-arch-test +++ b/tools/compliance/riscv-arch-test @@ -1 +1 @@ -Subproject commit 46cf99d0e020887e398508fc776928a1adad7c23 +Subproject commit 9c65b8c25116bdc3628cbc7024765cd104a7e42b From 04b94a75eaa72666167ad63d5a79d7b16ad6d0be Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Sun, 25 Aug 2024 18:33:51 +0100 Subject: [PATCH 13/88] Update notes --- doc/Implementation progress.ods | Bin 19140 -> 19678 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/Implementation progress.ods b/doc/Implementation progress.ods index be8784dd3f91ce9a0cdb05185fe27b5d500f1110..50390731a69fbd8f444c4000e9179d17630a1363 100644 GIT binary patch delta 18046 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 E0M?kB@c;k- delta 17480 zcmZ_0by!OHr6fMCD#Vrj%ixs!v6c292y*R<8KyiY*OK}PAS{zD?lood>Zsnuz zx#!;RoaedwkJ zbX;?w@#{npveiqE;7m)+NPQwLL*29**_5?}Bw@(NOs?si43ragy2$Ye3q$H!gvGNab=vT@ymo3z5ecr{CL=Lz-!Seq;#xc;9bFWR5c;T{X4X^p{vO? zXzO8{O&eR(lV|#ZFHM&8%}Rsz_Egj8hnyX+hc>n9CJvW0v$6I8`P26`hjn*rSm(z> zFV1gQ`^?`1muc!#2VrTtf@OYFSocQ~qgc^Wi4pD%g~>_DEDDWL*yHl41L$1^tVO@z zvwp)ArJ-x}tP1ObKP@=9P9-y;66|Zneyj!pSM0EhfVIR6U&(+;{wFnH%DUEv4`UCg zzTqs6_!vHQ9$TG4f?gE;8_LPDyk-K|V~snHnyJTgj9zlzbB(ed@%uKCSNv>JQt305 zf8HrSF6K6#Jx0dryryt5rr{0kYaY6emLp*mKOie?;jtwQSqLTx9Y-;S5_etEjdiO* zFtN;2WPj%)BO$4vA|d^k3jX&VC)wlEzzp2h`AGv#YD{*&s@$7U)47xITSP#wX6tRJ z_>Yb?<#hX6?F_y!Mig~-$u(P|^$yimL98w$&Gw*T{yV$!;E+k9cW40{IiTYi=V|+v z&l&i{LZrU=!XJM6`3(l1?lo@sVQ-8mXVI)uNh^;b8r*o(cGM-@ZN+BLdT@d0d@zX6y_nO8^=Y6 z=Sz|6do^eSMT$9pq5q)~KGN<>gJFcFO7y+H7XJX8pxKrwuocv>5q&Z1q2<6xpEJ{<&AE$;eJ+UX#H(UnPZlx_?7_*pY_T`8+6!~2*VSxc_JptH=cBs! z-HrA=CPgH4X>HeVyGdDc4ku72raRo_j~EQbKFDWjFcSR9Ub&Iv{gj@IWeOW+7E3_g z`PjZNSqh&I*-M=nTHKex!e=e(*+b+IwStriS`JT6d8gSA;5M z@RPMrb&gry;;8>?EPwCM*-KIJw7nHwMV!e7G^|#JP{Yn>4@2@O;w;h3gh+7y)Srm2 zTEGrqN%9!6)EOxbtp#5!P6L*v4{v=-An7T?RTtiy6!1Z$;*%~rYSw(&F zf`@-wzx}A-BIho1zhK%6?Y97vPG7KP3GJCn6NM(nuS(?9rE-Ll<}%PdbH~;x{tMm8 zBvnbRTy4n+JvsB|si`Rq6K^*L|5QPY364JkcMOg(>R7lGjN!z%B2O@vX}_S?W5zaM z8>xmm3ym>-AhxNv+QtpTOGaJdD3RYiZSHYta3$?_>bVir?WEe24gG}5V25LuzkJg} zyjIf}1jRtAjd4kLRhetq97EE*Dw@IIKJ6a2ssWW8l+m48FY2YqY|GuGDD2DLxRBa% z-b-1IU`8e-uTX)K#&>Ra%6wMjK(cQ{(}WH3`cjt&9NRsf{)h2QqZ&7F-t3v3S*B%Gpb8nj)J z-e%dOcF_G4Mt*nf@eu>4+kx&F^o`^TC8{m}tKsz~F@$WD?UO&O4$SHxzPBDJN_)G@ z-JhhFlxgt2Nf&w0WYjt}%|4;I=tCRHnvN)u*`Km>5mF=qwd5V!$j*xgHit6QeZqGH zMh_&KXZvnq02DqvsWclctnF1}2GT?3UTA=~hdWggbMx^_cT{eK{7t#g3G2hC+QE(~6bE zIQX#i!t^)z^yuo{m6GW2r`rz892*MlOWLcHl2NmXB!YWjCFKn>m0!2^Y1@69TL8w$ z9BS6zD3WD-2L-;53j~bBMKRGb#BT;mw_UzZ%a+x4%K>|bwB*?@7rQeLs}qh} z7Q>JA_qure7Dujk3-jBx+mwA4N3UbcfAY=x`@8sxK3LW;h=|n^84<`88e-^fUGAJO z$8;gO5GyBm!nIycA}in}Of6ahPJ_U&2L0Pz7y@lDK@;F&N^=`BwMJR<%4NFlBdpHH zTJq9f(z0ZsA!=bY_08(Utg+;FF6P(bQD2(78iQjm0mcGv&)%YVxyWAbyP;>Q27%=X4ZHv0Y?M zj72@z=@2Dj)diqSbP0pKt7ExaoIA{6~GAB$zBI6n6<)OEcew)EsJ6XyCB?e#?b zcoiR9S9bp@)$yZR?A|KjzRl&|f%B*5sE3IaVc`Y%j)8;}sQy2rAPSF8k|7E;%)xEB zmFVwJ<9zj!?2jcN1-6fz3#mJ6Uq@V2Ts4LoeDE2rDo^%j=y|%K{>n^_?cJgKw;`Y{J`ZVzMUR-L3*N~I9hqwIh|1SzPq+7xU;%l zS9{SwvGO%{li5QAt>QrKYYAAv;J0dkU-zCyb{7284>)&+^+h=J(w^e+_>*xUXqDSJO=U~R_RF|wf;JVlvfp?&RGvsiG z50N`yja^>&ooTjA;0F84RN`MmmL%0JS?GFoHY{;)rPrNt9-J?~>@o*Nq%g9Ek=4Z} zXa2~jh$a|_j7ONip$`FsY>_8}uV0Ypel!keL~L<3qG4~NklPx=b$w`eVwXulC%Cp! zn8BGEQrkBT8E-hlXc=lp*waSo-|q(Le*0oFyKVe)vV9IkFAi2qfu-7C@m^57aO6cc zQ0~6NgS2vBCTvPw653d&$+xt%GQ{8y_)Es`PLBwT&3+B3svu@*knGN zac38n1hgVu!5Bc5Zl@b19qwhRfk5=)$6-G6ZG^If9)SW+M}vtcL;;-EWW}6Y26rrX zRE%?kS$W_+x-BAjLB7hba=NW%D6eME#Pg1{&0BQ8LQq~wM4OY-q~HM)as&W=109Dx z^AUMQW|}|X{wbopDbX%Ez%ET4;1Ki jcFWO%EvboQs#I^)Ryaf5OBvVf2>0Cz+9 zhrgE0?D6V4^OlJ$u6z#{a&Y+|*@rl0Mnnk=zfG#VkW;qu%|Oib;j`E#qPsU)I0(EbO^%txJA{ z1fIuo=D>zT*V_Kz|Cl11u}7p1vl(^BiLJ z{o7WfYQ^FrS@DkKvm2(0h4II{J9=%^HKU&apxrK~@t}e%w3tLu?`b&LOW>fhTcymM2{W3~4V@dQVt9H-{ zh*>IfHz!6Z7Ej~TRyx?e(^Se(<~eMB%xf=s^^?p4+_gO;=#yK$V36rl-o}_7)*vHj z5N;)c$mx#Wq(DxfTmkk?{at>!l)PPxyR}P=LyamYcr)V5eK8^|!9AI;#D`)&0IS&{ z9`1aXyTI~iJ2-AzROwzv>d3&UFR;~N7K&)Aoc&y!Tv5655x}&zTpB+O3KNHx~L2d4mqA&-~vH;s1FY5X-a3h@A7uWyR`vSb`Ay^tB!P*o` z{m19i-O)?oGAqjV)APza%wI9LnH-N+E;dhF2BCP@+s_yKF2Pbl{YI$DFD=sLiAAF~ zzp^3#?*?pFbgAxCo9ypps;B85m|aV}&3(VMmFu6Sn^bR6xA1?Dp3D#Qht;0Ei5sx1 zd->)(Heac8tk@oAi!~u$d)siE+Y@|KwS8}V<+nKdopSc_N8Rh7zG|(fg2*-7F@6(m zo*-X&b`J?EU@9Fn=mXzcsA=9)XnvC zf=+FzZxJ~8L$s1`Hg40?$?@3J=hB1rR}#R2THV!9=)Ndfh3>2@ZsewIz9pm7Skc%H z2A!F~@~++2e1k(rR7#CQA8|_ZHv6JZE=;i)6Vxu zhL=*Y5+*aXu*Lv3@_fIjNY;hq%0E+d-DrM z+Z0rnxP$J+G9j{H47nAdh}oV*R=FlP+B}BflC&YX;*bLs6dvWa`Y8ax()u>vB|2ZZ z`$*#xJ&dk6!-QyMPB4-s4BH=fQbvcFoIz>BR}kap>$q=NCS5FbOtoz0_~F-)JtY?$ z+?I1F@(XPA(bN9TOE*QWM#cM8LfxC;#xukaJaNZPDM!dD#;jGsw{ z1^8hm|9YpUPU@aiPuCadiIlmWD5xef=(Ua3q{40agKvBbQDJll)wWm9MnUT)ZX?jO z(rN@R_;=#{Do;u@szUnaiAtSRNhwEfsHC_M9$|YhCZ~Lm6@_o*McKU6gS?uIS%=tQ7H@)LY~MvyhWL1%clUmEEYnCq^!3@XnxDacDUc z4_y@vp^Mv*nYig}V8v;-uGD~{{HJqX_l4Fm+MfLHodO8I7u@j_n>D;_e4JXPEJ=DU za;rjgv;*j6b`CpuHi2Ct(u`c05!upnR8X>vOrEs$Vx3sC{WN4Y*$R%!l9| z#x}vWjE&DS$-gPzKjxzVWK-xbcpH*R(HHqUrbQYPKa3!dw{ z;W_nvsWdXFE?1>qXzl?GtlCH^Nayj<`lMDLd~BGlb?7wzo|Ldq!y7aFCS#`Ae6-)% zPAy%CytDB=OY6+V@Ly8Tqi_cTSPJgy{TKgu zF6c@9S2u=0FP?r9t24GZda?p`N9TiXF=RjO&ujOc?$s@>)<;7Nc*|*05IT{GV~Ii_ zvfPii6FCv`D|Bc_F?yFD8}=7`KEx_M9G0;nA(gQv3DQVXo~tRnmq9^6 z!NbENCMKq)re;GJuHPZLBlWzLPtLzbkBE^Ru{{P$9;^3i&|5pS1{~mE-hA~jz zY(&2kqt5N%rAivaTjK4wYCn5j?(Om0$e$?FXm9ukrN6uP)8mUbdxRDM{{0e;w#b+W z{GP~5hpoY*vg5*0I{E(xff={H%-|Q#wQj?3^M|ZN{M7gUoAR=eN7HS z1qTdnB0d7BnV^y_)nD-yeqna#^&Tk1EK=RDH7AOXpJX0=@^GpRHD`J>?IU=>5=tBM z0tUzmL|#LdDlDsoTj z#Rv3o&9<~3$vZ*ZMc!DgE$9U06V`6*9fZkDnL|p#tz)7JFV}kmLz_1MZuPaYU$Fc8 z$LIqHVBvP&L!t3OztjEer@!ju^$T}m*I^C?<9!W!TM_*G3iI<@Pv286$EgE5O$=F| zyy~~^vAso3UZFX`=!W+AD>==@ELhvWuBzhg@dQ08z4RUx><9Q#k#hkySM0)ZMVN5z zA!qeo%T(@te5k+tUB(8lgzC+h9=Bka3#-p+3O?-8atRLtDO6ux}}0@0SD z(#yWkuC~x|A$QkU%Rnu{{KZruK#ygOmBk9nK=9|B9~UAIy4T1h7N{XX!gRD9h}mCn zz9%&^Nd>CmVh@3OdWOvz=!}qFb~8^V-;m;2_Yue@D90#cU`AV%*VvBAFv zy*OQh6iKlXKOjma2$J#ANw3_c3?BK* zT~OrS=t`gtHGDcBwo(XdS+eJUm4Th7k~&D6ZPBxM8-s=ypB=#+eThsXu`6SU0UN4S zof16z?bY0#Hqpd2h=u{Gni0b-(QK`2Hc6WPap4nH_jC3f3`ZF7V1njm9v1474meRK zoyB#hstrkGMXdnQ^Wb01W@*!BFGxH`WQ|+T02D*a+`W}{2Xv?T=0`Kmf-B6jF#eiA zWXyA=JI4huw6zk+)MxQRuCc`rcGFBN9RI2(B@9Wniba#ghyuuVM~dAVAIl%8V|Agz zF6<0xalk!ZEFW~FZei$kM^OE8+7ytTp z@Qv<_9bYp?E1_F1vN=Vj47X~72%hFu=qkhcI|uH-1RB;r5*$2? zq1QBSuH#6c@A(Zn+hMeZfUc8>FK`3dkz)hn^K(;M=PaR`OAB)&Tfi@zUBHYfjw260 z-@zP-5eW{)5t(4DgHU8Ij7ihFojWcSdCi=r6t2gzh^MJ9rex|AIy%5?PSud65)>7u4@j>cN!vS4x0O^ zE3p6$XQP;w0Yc{o^0wt4XO_%9zqaUqpVp&H9eiFKLQGTg3ytO_%)GWTfN=ODa*PJPuF@mXBT4Sh>^Jo6)Z zPff?RDSEvmPp3cnz{K>_O?)%|hW|C=&&<#x$cr-^*W*%xmE(_mt!3#4?9GI5{aV#K zYd06BlWHB6b$+ERJKzz~+(hpdM_Y!8i9?-6D$M;=xyNJaGhcx*mJ`8u>>>ZOX5S-nuSF#L6O26=t)`~BwJ_2 zyf*7(VDOynS$(2byn1d2fkWTc8mCg{9EQxRjSQfy@4*FDEr_DGruSy|yEjWWF+tQ1 zOy|FKjO~$)Ee$#@rf>D%8bKepK8XPRkh(i!j^akoP|rqp)qTQf_!Sg)yt+6x#;{8w z6xZ80ygHd~>0u=AXl~@|#uMEZDPI{^ySq}EYd)$EODg1xL9eMlW7-o@G*~X8`1Vd` zGsYngouBjgQ&X}%x=S(CJUr~b$@T6CdLi`b;~@D_!5>`D59&t@cT-eIA%^yMaBC;+ zT)ua^21pE&dxNjPc(w$FC}J>JalE4LSxT9>lhhq#?&E@OY>>2nTSE}2zUnT*^xvrC=qb;-4Vc)GrZ;%_*;+Ld^^b(q&0|Gsn_Kg-QrrKinH zSJmIgcX6RsWhvr+c_MoExa#ElWn*68Y3W3)^WI}kYn&p+kMa#f%Fd39(dJ?e5P1o> z&+YzO|8xqw7F{&OdAwUFefRgi=Kjkap5kq7q&MXbFZnze3?UNAT!K90Q#`@t}gEy~o^uAI6`p zFCi+%a2(kw3NL?3fR%|__^e6j$ooc1Y1qTjQxscDo<&tpzW=Q|Fvq38EVm^ig#Qnv6N4Jo;^dm8bKJ*H00?JB z%TX*u80>@*(?Gwtya?bEhwktlw@rQ^q=-GSU^Mgdbu*!h68ohuevF0j#hV!e?>$eh z!y%u_Nb%%tOfpnaWt552u{x+A3+m%znGEaxZU=JRD?c@6@t4hYkl~7l$jSn%-A%V$ z=-^!&Z`qI75RL6AP}`8H=MCSL2gc4hV==(B!v#T#o5bte;EY7b^%Wo_!6|v9m{)Dr zOOnf6hY7AG1rM?vE&hBP^KzuPNgh-{>AI(%>vD&9jhL6nl^8A7JE7}fPlQOqdcPlu z!AF=>u3hmF^Ys5nIph`=#0v=Ok>V6x&=tBX_L;s_@_)ucMevS~6f?5G!-IPR%jb=! zEms5TrUZZUv~BTBCPC`H{~%?6UtM}`ABh!W$?o{cav`Jz>eO9rxE8^!D--x>UG4WV zZkrmMKIken=jWxkcduZEKQdbqAzU%as|ip^VOp_5tEsqk9!K2#!h`0cjza^|+?n{P zcp9*dpDbC-Tqe~jE>%%@`QqIpd+u2vwIDhE5FlYji=&yupokv%$oE^bo;CJH?Ko)+2w14lK98%bLQ4-jD@8cx z7O~{3wa4(A)|kVvEa)e%Bin951n;FToXF)TrMpi6R6A~cdx*)}|;`96L8krJg#C)(RyADvDEuANd zCzl?AAayB#@u<-t+>^$|9q8aDX|KEL8WX=-ugD-qh}09m}~(S zW<@4Nn~5f%Ph(89z>vRY?@7m<^**cwL1zWra4?$P@eX2yS>Z2U!Dnm$dO^@n=N?`Z zHxisTnRecE^Y(=fOI?2J`{19AuGp*FV4Uuu1OmM-X+%}tc zW$Qd&e(@Yn*+_qyYIXlu(esM{qs_a64fPxoQB|UKRCv|$Qy#f$9D`wgQg2r(36h26 zjRpd{vWdh)u)liQBz9a#{k0v3AzZW(p_Df68g<~p=@%Vfy)fYr zHy3SEESE^2O>OaV^9&KcA(dT+wq$OS?SXDt?oOK%qTHD z&vFigzR1`YqQG>uQP2+G+NEWd!&EUaIrwbjD2=BnQ*zP_vzhN~7Q{x`5C=-^Y)oX} ztJtFlJiMstK_4t(7g5^?3;(3dhlJYsi{5cmu(;;~aZ@btGoDd>C$okLFLL4SWIQn| zAXlPQ>?bWnR`b4eu{D(T)5q#%iU9oA)OIm)PAZ6bUHs3K)hh-KXMi0cCVjV2RZY>2 ziLsaXvI>ZKSdpyw9?3%rM1zZ=IAQ2L!a`!sI+PP{j=QQ_7o?I55&6VVR{{OxSdDOp zjhm>KH8q#CPjW{GRyCqO2+t0b4hpLSvsG2x_c|(UCW?IxFlf?Z2D#7mQ zAaFhT>P0U;E+bD)bDEnCT4tUQp;)e{Cj8M0fMhR>l?~o{#C+K7I=aZYJUe8QE%rg7 ztk|U-@vG5`WsFHI&@bTW82;E~kYns4|EdHOqkv!$}{W1e*5fv<+l}4)&_n_4zWR z1H&a^ur~L|Hk1l0KKK%AYC6S%xCjN7Aq!L6SGznp)R35o1TT=$ET7SGQ(qB}qU;dr z3m~wN%*5o@VO5RbcF_IDL#t*Z11@{7PggkT+GpWd!Ertu16hg@85#R?0clCjoJalO`RuA|3E1E)QZP*E0t zg;Vzm6~q8)e5sj!2f-a)DlYO@2ADJ6Fn>o{CmQTf`V^!!s_xZWb%jElRca}J{cPe< zz@bH|=Jq7u80xzh4ge347q*HY=q5KcE{2|$PyNL~twut|Vcg*Q7U@r` zQ23Vt@FFoK3bMDGNgfAM!Uxhnw=w+j5M|`@06dQc>-hwTgd&iJXA3(LwiHmM8tq9! zSC$Ih-~ZevBamoU|X|axHe~R;I zD0Y$|i>Seq@esq!o~ZH|K4)V6_BGl$jH z24={*iSp_%(z8q1oE4f%W*G-(43y9!J!cb%QzJ|rdQrdoImVbAsY+?p5saD8bt0V6 z4UH96=Zlh_*2Igh7xD6X;S^#U3t{0mCAL79yqkEG4Xg1FI4~??>5%Rpjb8Xj<@E5j z5C5DeSRvFg9fu&v(8Z(!>b5rVg6RjrMqd!2U!Y3V@6_d^7iDr2N(Yk;d5o$M?znVKn;I|uF_fcO zet>}$2zSxFmZ!6+xCHVyNgN7)0Pt_nwrRV(2zq#ZqgQHIGUiY;9~@X&QzyJ&L26;K zdJY(D^a|+twr=`*7;IFDaA$fRFmauSG9Ds;3UiI2VBeZ`P+uOm1?C^DYkq>-Qb@|_ zptz12$OrX4=e&Hl6vpuU4~vz^>KS6ko3mtrS(-uTITNXHkT&ca8YqikpdI*L=-O(>fX>#Y2J58u!cx-)5o=Y8X}a=zVC=nd?MxCUQ9} z5n{L!X7n1aE69j0m1PMva@(u#)J$*qr2>?>W`Pr=nsSDn0p83*+w^3w;x~!WLym&@ zL-mI2_~4E!Pf!h@N6WUxDu{_RrhyMmd3!oshIrqMmrKSJ-Bb+%8Py=%5#xelFh(*lA;6=zXm$`M*=MmB!dT$sm>|hzXFOrXSn_VZd=!!h(FIY!F|FSe^CY_}yvUsaE!U2zk7Q1Lz=^Dn!7zd1$lo55 zv7h=bKTD-4GGotW#}3F8qg?RzRPx>8CNA2>RtBVnKwV}_1Ji#f2nNltb4wFLmz7jn ztw$@B?B?U5ZA*min+b*{LU>k#t%HJW^!aC);6`N#cLwy&XbF%R{}CpqO=2rRfndxZ zkjIy8jgZsZ4OV!Gzgd;Wc-m~0SH8)(SNZm=R$#JGO*|y~9Ppfh9VH;rZ}F&BMx;R$ zH4D%-qWEF?XiO8>3v1$W%96=v9eV4JMJx$il|!KQlb*#EGvUYZJWCYV5p4#TZ}J!l zf)=DoFk_%gjoI%PXFzn2HGDS86@ebL+Zu0FdV5ko?+Jx;H4}*{Ei6E7@kY#x1|hm_ zFWLwQ=Ni5GDig9df*h4zB@UL8BIc8!wuy-I!aSt^<9XF#G8IkkG{P_=oOgR;x1>v*4Vy(nZ>p;P=2S z8oM_{VAzo`#7lOKQXdC5zm9Fm>f&eVySn9EGfmc6$7<`&d9Z8=Wf59%FAgV@g%#T0 zZ!`(>VEJyCU$i|QHD#a@Oi)ud@*2Pap0i&rV*4zzdf@vRVBwU`;e`!y9iGol(=KaM zrlW8%O~Z*ncR3nd;dA+2E$!J6gx=NHWSXV{gh`=LC?Pfxdmu{{Tqos;L3@78gM6n; zpNh53uO)sCig&afwcj2#?8nS*b0hpQFvvAR6q;77r%@n3gv`@~PlK|%7YzFRUd|D_ zd@m-c7SAltAwk8k3TA3XiC`HuO^rgr3zK@5V_8X$+P`L3i~?rs z@2?8N!AtC3D$+F>0{^yGq+$dvYHKD(iUA!#bXVWvW;EvOMrA8T2 zGShpNSK8A`LQxevizZ~JYw^ax-aal!QYwfZA8&|maDbM^=r}e?KrPipAh*s+;@q8| zjDq_|MqPc3a9~0L`6O%Zx6e&MJ3%nqH@e{&s-x)UStWy+4pDD2rnYkmIX6Bxu=NkR zYfx3;HK!=!qTG>-EHbgCzvoDVU}M{_a!=s9gjb#17p6sJ$a0zo=Z|P(n^2EDuelT< z6f%#M7;j;B9v>h{qzLY#uVDM9JFKAh?bvvHL0YN#lx&F*1);dGs6%d17;V+VH@iDn zV%N(`f~4Br5WZD@rKfA0y|WSB7W-A@*@^H}ZXFtC>KI;XSFGr-4HsV60L=n6enYV6 z`%-OXK??iJ>?EZmPElGFUUE9T#d3XdK7h#pfC4a@Tsq7^#r2YnTRrL5S6~G<$mcPj z<|SsivF_I1nR~s(i~(f}EL-!jvX~b_+>`dz`W!&;$CMosR~lluIag|qPPf2_uZd7% zQ;mzbe0#avD;-3?5VR2-yq8AnR8ZXuGjP=Ytbo9aN<}`vn`<29gv7zsqQt6rFw#=Y z!F!a_e03(jKx;Fj`!twg7hb0)R{pHRq&H(hxP%e^RG?bMLVS!4rPNMr28ZTZY30z@W?A)fSav0u0Q9_z))>%bkz=Cr)t6Xj z^gcE5>VVchZ`(1^JT_1zSLT+kS%{NN?g$w;!r+r$yX5i^B&nsvusIhLc1c-n3X zda^`#l&R?BX)|9vas8QyVl*b0&@s^asfmo2X?fNzF_fwqQDbbMKOB;6xilT~ocroI zDqcvfNoStM{tddWPIis#C);tAt`yaT#3DupHU*@@>JIF^i-vJY$?bq_pkw2077dd| z%orL~cz(|>wD9`pLKzAJs#F5R!(_mwUxX7-LNfI|rffkrC1!I=9nkpthtb6hr?Gm7UN>!oJTJYA8-gKxWp>#X>D3g#r zte8EpoPH8q@ETF{4ZyV2Bn~VV>vuEMF^!FZ1^32HsipQ3#qi(bAyZZ^MXd7xqu$_7>n@1o zkWs)V?!D})Y{{#x(F>o`9Tz|WrxX&t_FPVrq$v}^`$X-+Hwe1E0hZR2l@0NKcugH6 zqUcDOYI#9oW8xkTmE4u{`Fx+-6_AL5!S#xSlEk}zeop5}c6XzFP3<1$KXm`xU%ujodwv4W7e_7#OvF2D*BzAFhr!UcK|{UQ<19#a;k_nh~qKX1U*yUw*yln})fJbhRD4<=D2&YHljJS>Bt6WE=0 zqUB~-iv4(FGdQBWz_omr6V4&_TEO4TB*7m(BT8Id$0^V`%65;;p+K-u!l=5 zszi1hGfk1ihZ+(|f=W74T<==mDJJzAL7F;J+}KLU9~#oDgK$n>smfh$JV>4L4^|bkPMLrQOFI<6b8>I zi%G>Ve!!>JrH~y}%Awma&69!AjdD+b%s3DcE3bj-6qs33Yc}A_Mu;62R zz%%?b?k}6|8g;F`TyLoqJTcU=sWui-)|{R$$pol+LX?P@G`;Si(2PM06MP8o}tnucZNewoqx{ z-Yi#P1=N-Y(+EkbXi6|1lBfgw<;O-f<0reNlt2ff4S^EVvP$>)$=Ve(&wL>flls8% z>CZBW7D|cHMcZ;-=5m)i*N^Kg-@HJi+$Wp5>b2|2eswO4SIeh8UmYJr%y22NQSz~ zT6~?Qc902~NzZ^hLkf(ucJqmla!Y%U8I$B>h=Y;!`(#K#hinRTNyAkk^`Bm3tU}iX zPb*v%e$6+_1JhIa6RZGGJ7AQN^*k#){soAAleh_wvlo1`2u-Yku1{H$jxwbw7t8!k z4R))KnzokKxWR)FNs(4C!F#}x4j2dcZmeO@eS%ziCTb04IO|*sKd0O^D8UABL|bB; zE=D9)7!K{rOgTmK&awk4FvF#9V?M@1s&{y%sc`dK7OW$yObaA;kIe3tFfeQzro4cB ziH~kK;~NRIjWVf0OSXVn{qbZ-_17>USqvCKid&lE3Tqju+a~rQ1=W9lUr@6Ld!*Of z12>DgsYXZ8=F@u7HYxY+;#&l{R6r%itVy|0A&oIUTeDO(NBVVmHYU#12uASBJDMK( zq7Zd$V19PS5-qL?GKKD!fAWb(VPJu8Ul`lHCVa+gG#EeYgPoy-s+QX~oC|TdoAbCNWJ#-$HmFoeerrlCa236Te6N;X)iI zW=P#2pku=PCZ;{OH+`HGb%;mc=lYi1!LxZBH?7iC>24PKH`)nbE6WT6Nfusfx$S|+ zU&QyEP-EsKLXfi;N(z|R`W~JQX3OS`9X7_~Vq#Ip=8IN&ie1f~^nn9lGG8)i$3*e$ z*ubu&_21`1Q_*)dsp|_MeG%nCTN;q_rLixF#;_+zYe71T?@1dxUf-a^6?@UPbL-d( z7wK-`6Q^FWs&s15>tma(Z3rrv z*7Mdi(RU7xB{xr&sRNrd=2*J7HS8ykLX|pytC3TzmLt$K%ddssnuMaw$%NYlUte*# zJ-hV3^(UcI@tNdP6zZu?$i@zPH%6&5H?9n9V6enx4Z&D(58)mOjudB@zECC9r|=o9 zihrn_vpJ*H;SA9~>{%;vEx(0LTw^-*MKlZOxkbr2e-ilJ{{ncBD*fOe;7BvKILRER z3rlPCN@;vq)@~A7$!8E2;f|S7lsr}Xj4IQl5s7!hY;H-9s3{bTTO9lc_8Sa1-NHyg z&!XTXyUg$Q&%=D&X?cDtx!em*vV^s;7rYV6 z_3T$Go=XLFF@!W23@#qS-)yRjd3kd968V(0TuFb548ePEhA{`&ele|CPp4e_^nY93 z>zdSEI(}i4tn6LIK~3s03D%bYy5Op0Q{%FMfH6xj*%d>Krz@+T?=GGI>mG;NK<{=F zXRKT|E5faipc6a{Rd_E|ynr0g#SIX7VnpCh=xURc2nmn{Dok(XJ|}hSVAtpJnN|1# zdak+@P(l7xU(L1#QM@P<{G*I3w#T@&#pdiUao|MpKLG3Olk!3WB=$4SY7}%94nQ!X z!(ueIh$9mIB9Ah$nMgO;oMrgLzD9($N|zlg0~L@%j3=1hGsFL0;HtiT@9yNPAURh4 z$u(+C()_t*>32Z7mI+NX2drEIcAx8H9_IX7Qow2th14^+s5M;uHQeizGV!Iqmg^|> z>L~aoRFZvDWB40D%askgsH$hrgEj>Mi+n|AEOsPxz_TO)JVQe}YCGVeO`TFp3>5wY z2wr*xc3p3h=bU?>l^YJI)CBOw(}=#hF-?dwl#mTyHU*T$lDuk6Dy+3P*YEiD3@8al z*__FD=-t{Y9^41`aVWO>j!A+72qk%-f zJc8Zb;S%G^md#{OUd1cfI2J|$A#*x~P}`k=1`)2Gi`|C|GbZ*PZ7V9o;6go|21aji zc==KWWP+Tsz;DRuMC|X5FW`CRsWf|TsxK(8gU>~8odfvb@gK(XY|gr#4}5XI$_o!d z(EP$3GTV4_pM9kZcCMVp>^kfS&GPM7X|tEZ)o3z-W>8(c6+r7bXt|Nf*3Yh^yX!-= zh0^ObLvus`de6|VRbBaH>0oA^eRfW^@M*dTNbq^l;GUb*lgVK>G4mo}(K&*8k0G@j z)HfV(uYnTjZPv~Dxy`2c6}2eFHFIQMbX;yDfM+LWt||QcxoAaelex4|I%sEVU*Vja zH;isR>=93l6YlkQGsi@F23Wv_yZ5T3wS@;IA@4h>@bDpC7+G3WfpGBIE21L=kG1~X z@yJE_$JxK{@|T3sQ;mim#BGoZJZI z|2TD0D=)5c_6WD0Evx(y z-Joa)+{~}T0$Ntd$RxsmI8kD9u?O@(hZrxZ$%j2eChq5%Y~aZykA8}SJSe>3pa*)` zgf!$Zh*vGj~lb?I4!)2KY87D9B)PPGftz?`W z<*5eePu}MRm3-yp1`*Bima6w>0-hz2n3tKBT3n)6l#&MX4(xOSEOpyMla&~+kja^OPIS;jLtz*|BA6pYBrT6s_u uZ5N$v=pzMIgjnIqz#xI5=)3e}8(Ap~tC3?>6h*^Tm&qG_)Y&}UK%xKx)s(mZ From c578c8603ddd4da4af7af653d369153c93abc2ae Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 26 Aug 2024 18:04:22 +0100 Subject: [PATCH 14/88] start implementing timer --- .github/workflows/main.yml | 1 + crush.core | 15 +++++ rtl/cpu/mtimer.v | 75 ++++++++++++++++++++++ rtl/cpu/params.vh | 6 ++ sim/mtimer_tb.v | 127 +++++++++++++++++++++++++++++++++++++ 5 files changed, 224 insertions(+) create mode 100644 rtl/cpu/mtimer.v create mode 100644 sim/mtimer_tb.v diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e2fce37..e452853 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,6 +16,7 @@ jobs: - sim_alu - sim_load_store - sim_top + - sim_mtimer # sim_cpu is not a testbench, but a target for RISCOF testing, so it # is not included here steps: diff --git a/crush.core b/crush.core index 1776347..e51179a 100644 --- a/crush.core +++ b/crush.core @@ -14,6 +14,7 @@ filesets: - rtl/cpu/registers.v - rtl/cpu/params.vh: is_include_file: true + - rtl/cpu/mtimer.v - rtl/soc/memory.v - rtl/soc/memory_infer.v: {file_type: systemVerilogSource} - rtl/soc/memory_ice40_spram.v @@ -65,6 +66,11 @@ filesets: - sim/sim_memory.v file_type: verilogSource + sim_mtimer: + files: + - sim/mtimer_tb.v + file_type: systemVerilogSource + sim_top: files: - sim/top_tb.v @@ -105,6 +111,7 @@ targets: - sim_alu - sim_load_store - sim_cpu + - sim_mtimer - sim_common tools: verilator: @@ -155,6 +162,14 @@ targets: toplevel: cpu_tb default_tool: icarus + sim_mtimer: + <<: *default + filesets_append: + - sim_common + - sim_mtimer + toplevel: mtimer_tb + default_tool: icarus + sim_top: <<: *default filesets_append: diff --git a/rtl/cpu/mtimer.v b/rtl/cpu/mtimer.v new file mode 100644 index 0000000..3d79cf5 --- /dev/null +++ b/rtl/cpu/mtimer.v @@ -0,0 +1,75 @@ +`default_nettype none + +module mtimer #( + parameter integer BASE_ADDRESS = 0 +) ( + // wishbone + input wire clk_i, + input wire rst_i, + input wire stb_i, + input wire cyc_i, + input wire [31:0] adr_i, + input wire [3:0] sel_i, + input wire [31:0] dat_i, + output reg [31:0] dat_o, + input wire we_i, + output reg ack_o, + output reg err_o, + output reg rty_o, + // interrupt + input wire interrupt_enable, + output reg interrupt +); + localparam SIZE = 4 * 4; + + reg [63:0] mtime; + reg [63:0] mtimecmp; + + wire [31:0] address = (adr_i - BASE_ADDRESS); + wire addressed = (adr_i >= BASE_ADDRESS) && (address < SIZE); + reg [31:0] data; + + always @(*) begin + data = 32'hxxxx_xxxx; + + case(address) + 0: begin + data = mtime[31:0]; + end + 4: begin + data = mtime[63:32]; + end + 8: begin + data = mtimecmp[31:0]; + end + 12: begin + data = mtimecmp[63:32]; + end + endcase + + if (ack_o & !we_i) dat_o = data; + else dat_o = 32'hzzzz_zzzz; + end + + always @(posedge clk_i) begin + ack_o <= 0; + err_o <= 0; + rty_o <= 0; + + if(rst_i) begin + mtime <= 0; + mtimecmp <= 0; + end else begin + if (stb_i & cyc_i & !ack_o & addressed) begin + ack_o <= 1; + end + + mtime <= mtime + 1; + + if(interrupt_enable && mtime == mtimecmp) interrupt <= 1; + + if(mtimecmp > mtime) interrupt <= 0; + end + end + +endmodule diff --git a/rtl/cpu/params.vh b/rtl/cpu/params.vh index cd522c6..63b91bb 100644 --- a/rtl/cpu/params.vh +++ b/rtl/cpu/params.vh @@ -49,4 +49,10 @@ localparam FUNCT3_XOR = 3'b100; localparam FUNCT3_SRL_SRA = 3'b101; localparam FUNCT3_OR = 3'b110; localparam FUNCT3_AND = 3'b111; +localparam FUNCT3_CSRRW = 3'b001; +localparam FUNCT3_CSRRS = 3'b010; +localparam FUNCT3_CSRRC = 3'b011; +localparam FUNCT3_CSRRWI = 3'b101; +localparam FUNCT3_CSRRSI = 3'b110; +localparam FUNCT3_CSRRCI = 3'b111; // verilator lint_on UNUSEDPARAM diff --git a/sim/mtimer_tb.v b/sim/mtimer_tb.v new file mode 100644 index 0000000..2844d63 --- /dev/null +++ b/sim/mtimer_tb.v @@ -0,0 +1,127 @@ + +`default_nettype none + +`timescale 1s/1ms + +`include "fatal_assert.vh" + +module mtimer_tb; + +reg clk = 1; +reg reset = 1; +reg stb_o = 0; +reg cyc_o = 0; +reg[31:0] adr_o; +reg[3:0] sel_o; +wire[31:0] dat_i; +reg[31:0] dat_o; +reg we_o; +wire ack_i; +wire err_i; +wire rty_i; + +wire interrupt; +reg interrupt_enable; + +localparam BASE_ADDRESS = 32'h100; + + +mtimer #(.BASE_ADDRESS(BASE_ADDRESS)) dut ( + .clk_i(clk), + .rst_i(reset), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(ack_i), + .err_o(err_i), + .rty_o(rty_i), + .interrupt_enable(interrupt_enable), + .interrupt(interrupt) +); + +always begin + #0.5 clk = !clk; +end + +initial begin + $dumpfile("mtimer.vcd"); + $dumpvars; + + #0.1 + + #1 + reset = 1; + + #1 + reset = 0; + + #5 + // 32-bit write to 0 + // Based on Wishbone B4 3.2.3 Classic standard SINGLE WRITE Cycle + // Clock edge 0 + `fatal_assert(!ack_i); + + adr_o = BASE_ADDRESS + 0; + dat_o = 32'h0000_0000; + we_o = 1'b1; + sel_o = 4'b1111; + + cyc_o = 1; + stb_o = 1; + + #1 + // Clock edge 1 + `fatal_assert(ack_i); + + #1 + // Clock edge 2 + stb_o = 0; + cyc_o = 0; + #0 + `fatal_assert(!ack_i); + + adr_o = 32'hxxxxxxxx; + dat_o = 32'hxxxxxxxx; + sel_o = 4'hx; + we_o = 1'bx; + + #5 + // 32-bit read from 0 + // Based on Wishbone B4 3.2.1 Classic standard SINGLE READ Cycle + `fatal_assert(!ack_i); + adr_o = BASE_ADDRESS + 0; + we_o = 0; + sel_o = 4'b1111; + cyc_o = 1; + stb_o = 1; + + // Clock edge 0 + #1 + `fatal_assert(ack_i); + // The clock must have counted since we reset it earlier + `fatal_assert(dat_i > 32'h0); + + #1 + // Clock edge 2 + stb_o = 0; + cyc_o = 0; + #0 + `fatal_assert(!ack_i); + + // TODO interrupt enabled high + // write to counter x + // write to compare x + N, where N is large enough to overflow in a few cycles + // wait a bit + // assert interrupt fired + // update compare to x + // assert interrupt low + + #1 + $stop; +end + +endmodule From 0db7967ebf40e3e72cb443bb1815bb6ca34b336c Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Tue, 27 Aug 2024 21:10:35 +0100 Subject: [PATCH 15/88] extract wishbone write to task --- sim/mtimer_tb.v | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/sim/mtimer_tb.v b/sim/mtimer_tb.v index 2844d63..e2d287e 100644 --- a/sim/mtimer_tb.v +++ b/sim/mtimer_tb.v @@ -47,26 +47,14 @@ always begin #0.5 clk = !clk; end -initial begin - $dumpfile("mtimer.vcd"); - $dumpvars; - - #0.1 - - #1 - reset = 1; - - #1 - reset = 0; - - #5 - // 32-bit write to 0 - // Based on Wishbone B4 3.2.3 Classic standard SINGLE WRITE Cycle +// 32-bit write +// Based on Wishbone B4 3.2.3 Classic standard SINGLE WRITE Cycle +task automatic write_register(input reg[31:0] register_address, input reg[31:0] data); // Clock edge 0 `fatal_assert(!ack_i); - adr_o = BASE_ADDRESS + 0; - dat_o = 32'h0000_0000; + adr_o = register_address; + dat_o = data; we_o = 1'b1; sel_o = 4'b1111; @@ -83,6 +71,23 @@ initial begin cyc_o = 0; #0 `fatal_assert(!ack_i); +endtask + + +initial begin + $dumpfile("mtimer.vcd"); + $dumpvars; + + #0.1 + + #1 + reset = 1; + + #1 + reset = 0; + + #5 + write_register(BASE_ADDRESS + 0, 0); adr_o = 32'hxxxxxxxx; dat_o = 32'hxxxxxxxx; @@ -112,6 +117,8 @@ initial begin #0 `fatal_assert(!ack_i); + interrupt_enable = 1; + // TODO interrupt enabled high // write to counter x // write to compare x + N, where N is large enough to overflow in a few cycles From c5d8d8ccb2c5762fb55866a249d45bc36933d45a Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Tue, 27 Aug 2024 22:18:29 +0100 Subject: [PATCH 16/88] complete mtimer --- rtl/cpu/mtimer.v | 62 ++++++++++++++++++++++++----------------------- sim/mtimer_tb.v | 30 +++++++++++++++-------- tools/mtimer.gtkw | 47 +++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 40 deletions(-) create mode 100644 tools/mtimer.gtkw diff --git a/rtl/cpu/mtimer.v b/rtl/cpu/mtimer.v index 3d79cf5..572de4f 100644 --- a/rtl/cpu/mtimer.v +++ b/rtl/cpu/mtimer.v @@ -20,36 +20,31 @@ module mtimer #( input wire interrupt_enable, output reg interrupt ); - localparam SIZE = 4 * 4; + // The number of 32-bit registers that can be addressed inside this + // peripheral + localparam SIZE = 4; - reg [63:0] mtime; - reg [63:0] mtimecmp; + wire [31:0] memory_address = (adr_i - BASE_ADDRESS) >> 2; + wire addressed = (adr_i >= BASE_ADDRESS) && (memory_address < SIZE); - wire [31:0] address = (adr_i - BASE_ADDRESS); - wire addressed = (adr_i >= BASE_ADDRESS) && (address < SIZE); - reg [31:0] data; + /* Implemented as registers to simplify the wishbone interface implementation. + * + * It would cleaner to define some kind of bidirectional alias so that we can + * read and write either the 32-bit register representation or the 64-bit + * counter representation, but it doesn't seem to be possible. We can at + * least read from the 64-bit representation below, but we must write to the + * 32-bit representation. + */ + reg [31:0] mem [4]; - always @(*) begin - data = 32'hxxxx_xxxx; + wire [63:0] mtime; + assign mtime = {mem[1], mem[0]}; - case(address) - 0: begin - data = mtime[31:0]; - end - 4: begin - data = mtime[63:32]; - end - 8: begin - data = mtimecmp[31:0]; - end - 12: begin - data = mtimecmp[63:32]; - end - endcase + wire [63:0] mtimecmp; + assign mtimecmp = {mem[3], mem[2]}; - if (ack_o & !we_i) dat_o = data; - else dat_o = 32'hzzzz_zzzz; - end + reg [31:0] data; + assign dat_o = ack_o ? data : 32'hzzzz_zzzz; always @(posedge clk_i) begin ack_o <= 0; @@ -57,17 +52,24 @@ module mtimer #( rty_o <= 0; if(rst_i) begin - mtime <= 0; - mtimecmp <= 0; + for(int i = 0; i < 4; i++) mem[i] <= 0; end else begin + {mem[1], mem[0]} <= mtime + 1; + + // wishbone access overwrites counting behaviour if (stb_i & cyc_i & !ack_o & addressed) begin ack_o <= 1; + if(we_i) begin + if (sel_i[0]) mem[memory_address][7:0] <= dat_i[7:0]; + if (sel_i[1]) mem[memory_address][15:8] <= dat_i[15:8]; + if (sel_i[2]) mem[memory_address][23:16] <= dat_i[23:16]; + if (sel_i[3]) mem[memory_address][31:24] <= dat_i[31:24]; + end else begin + data <= mem[memory_address]; + end end - mtime <= mtime + 1; - if(interrupt_enable && mtime == mtimecmp) interrupt <= 1; - if(mtimecmp > mtime) interrupt <= 0; end end diff --git a/sim/mtimer_tb.v b/sim/mtimer_tb.v index e2d287e..583e965 100644 --- a/sim/mtimer_tb.v +++ b/sim/mtimer_tb.v @@ -21,7 +21,7 @@ wire err_i; wire rty_i; wire interrupt; -reg interrupt_enable; +reg interrupt_enable = 0; localparam BASE_ADDRESS = 32'h100; @@ -117,15 +117,25 @@ initial begin #0 `fatal_assert(!ack_i); - interrupt_enable = 1; - - // TODO interrupt enabled high - // write to counter x - // write to compare x + N, where N is large enough to overflow in a few cycles - // wait a bit - // assert interrupt fired - // update compare to x - // assert interrupt low + #5 + + // Set mtimecmp to a very large value to ensure interrupt doesn't trigger + // immediately + write_register(BASE_ADDRESS + 12, 1); + #0 interrupt_enable = 1; + #0 `fatal_assert(!interrupt); + // mtime = 1000 + write_register(BASE_ADDRESS + 0, 1000); + // mtimecmp = 1010. Should interrupt in a few cycles + write_register(BASE_ADDRESS + 8, 1010); + write_register(BASE_ADDRESS + 12, 0); + + #10 + `fatal_assert(interrupt); + + // mtime = 1000. Should clear interrupt + write_register(BASE_ADDRESS + 0, 1000); + `fatal_assert(!interrupt); #1 $stop; diff --git a/tools/mtimer.gtkw b/tools/mtimer.gtkw new file mode 100644 index 0000000..bfb23bb --- /dev/null +++ b/tools/mtimer.gtkw @@ -0,0 +1,47 @@ +[*] +[*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI +[*] Tue Aug 27 21:18:16 2024 +[*] +[dumpfile] "/home/barabas/data3/projects/hardware/risc-v/build/crush_0.0.1/sim_mtimer-icarus/mtimer.vcd" +[dumpfile_mtime] "Tue Aug 27 21:13:57 2024" +[dumpfile_size] 1370 +[savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/mtimer.gtkw" +[timestart] 9070 +[size] 1910 1001 +[pos] -1 -1 +*-12.349197 41520 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] mtimer_tb. +[sst_width] 273 +[signals_width] 347 +[sst_expanded] 1 +[sst_vpaned_height] 296 +@28 +mtimer_tb.clk +mtimer_tb.reset +mtimer_tb.cyc_o +mtimer_tb.stb_o +@22 +mtimer_tb.sel_o[3:0] +mtimer_tb.adr_o[31:0] +mtimer_tb.dat_o[31:0] +@29 +mtimer_tb.ack_i +@28 +mtimer_tb.rty_i +mtimer_tb.err_i +@22 +mtimer_tb.dat_i[31:0] +@28 +mtimer_tb.interrupt +mtimer_tb.interrupt_enable +mtimer_tb.we_o +@200 +-mtimer +@28 +mtimer_tb.dut.addressed +@22 +mtimer_tb.dut.memory_address[31:0] +mtimer_tb.dut.mtime[63:0] +mtimer_tb.dut.mtimecmp[63:0] +[pattern_trace] 1 +[pattern_trace] 0 From 040c68dd5b7b6cd00dc6d451f11b06716a21ec31 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 2 Sep 2024 22:12:07 +0100 Subject: [PATCH 17/88] WIP implement interrupts --- doc/Implementation progress.ods | Bin 19678 -> 12984 bytes rtl/cpu/cpu.v | 45 ++++++++++++++++++++++++++-- rtl/cpu/params.vh | 1 + rtl/soc/memory_ice40_spram.v | 5 ++-- rtl/soc/memory_ice40_spram_wb.v | 51 ++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 rtl/soc/memory_ice40_spram_wb.v diff --git a/doc/Implementation progress.ods b/doc/Implementation progress.ods index 50390731a69fbd8f444c4000e9179d17630a1363..e9f35fef1253291b1d191b4b0ffdd13ff923ca42 100644 GIT binary patch delta 11028 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 T_CLx1Be+VQ7EXxyH|>7`l!sdY delta 17784 zcmZ^~by!65yA}6f#oeVyaVyY5p~We1^L^)c z?>*0Xo|8Xj_MW}7_sp6l?|N6#X}kRy5l34M8HE@D0RsV{HGu+xqk|0Z(rJ-|(En#B zJphqD9RrE@zvE4a{QvC(5C#9!LoDgjZ4e3ndpIZjKUe4>o&UWVV)@^DA#?QUZxIR6 zF)%Rx^M-UF5+^7v?U!;5*W85ToGpurxXOl9LAXk)91bBBLi4YGkNcD2?8fm_m7Xl| zjooV_W>TCOk7vj9%;`bHA{Fa50@)8sn3HmE_Bde$FF%*&EChSkU-lA4-{CH>l5`o1hN=;8^R=Zb-iu5;|?<;B^c_2gpHVnWB;T)C#7MoW`HtnrTxe(uy? zFeeAsLHu`GmYwv*K!V!8{*@43>~t=_=^T9Jz@OvIH_|(AsFoN#jVuSwy;j z;{70)Di*{ zPo)yo>&Rb=W2xTNDyKR$X}HGJ?08ov&#H|8GfB%ql1kC<<@uAwDzh_k$;65Q&!3X( zBxm%Kb`4DvK9-oQ%*Sz+T`%d-08FZoO~&Hm~fJqA!`ZDS|lQPyTThhhxV!ektin8z40x<@5#454YlE=wky z)ODo-E*~S^!LI1j576ve$i-)>N0K+0=_%4TAmdfLXQ$b}j|{G38dHY`gvI0+@vdc? z)8F(>z3CL9)Tx7TDb&fQ{pg^u*zEr1CqAYLF8gB9I9@Vdy{E3>#YA4Nt%@)hR~61V zrkgs>=Yu&XDQU7ma6jkzkOFS8I$l(>FKW8b>mR#~Jks&NC?hR@RfF=urZ?|nPP|1o zKtJ+J4a<`+m!8_4Q1ehE1=OmG+jh^EO|<5+| zFpF!=b@{5Ou8)aFN2oweRwu^vdwFHq07>&P%UWcwR6WF;+$@PwnUD^KV06Yn1U@cN zLK*JCLN1$jZvtBEl6Tr|hMvDs*pqBqB!pg+A@rl|IM@ zFk2~@qZiS2n_IFOx21y89~AATZ^Xe`zt`2)w*`r*p1)N2i7?9;S@4aqk_06nQS%;X zQK}O?agBVI!erLv9>h$~KxYPBFr|f&W5>ShCHdl~iEPvNBJk6$uT{LBf`87HZ&Fuz zaxW6K+eEcwyH=3@Lww+A)>%dE{7h|fanJ<=G|-Oc9;@~`cze>fR;3cpdQA)~sMHbH^bwj5%j@N_rNxe|YSLJ2xBr4rznHTn zX*O?hKM{9g$s>RKF_k%`wvL#L?$SzDyQnXjPD$ldIEC}`W@+;hO)7|m4LxrO)v{_1 zsnqn6wyLlxe+7rfsu*MsZvN5mv~S}}$~yeWzc1o#h_JHE>4<(%RPP2w=_Ze}u2fUpFf_dMZT>m7*Rs{TPT~(={W57*ai`5Q zX*#KY!@u8KrBn!MiQBteO-&8FOL=KcdBn3BE4XmHIu1BL#W02)yz_e_L@)k3;SGiP zr2|#3me5(V z6AvO>)ySaEB66P=h@%ow-;{c+69ZM6-o4?;iP#II#uZ<|Fax!t{*VoeLGe2}0Q=G{ z6gjA47NZk~Z;NtsBXxGIl&@)CK3Y7)q;aqQ8DT}MO=(usXh2E zoPK{*?=w**cB$oAdPDkhE|rWG##UlZ!0$f-*}lAO4O&0lWAM?2U120_B2G1}*6+&C zd}1G^iofmFmpo&x|HKZ`;6!`}N$R((Q1Co@q3~PPrHiDBsvqx zc|5E9q!}$w`XR#Danbl>YOWM|T7MvVej``ST$W0vN9-QAE-Sb+U+&+AC5AAY{k3<| zedoumd7u3FCwF%@xB8yrBI*fBO$QXS_f4TPjyF@Y0ohm9wWCSV#jpBP?dHo^IG{my zWP4-VTHCtZ8qz|7Z^pBh&bQ%Aw2ic&Bs=)0&x}Z+&EyrrLYh^qMEPV#U=S=R}VM zgM9DLQj-}Y*j~{LOPE;p$dS($JTQwKwjR0HkOjNp2NhJvBHj`Gs5R(zkK-gw?^GRSw%+e5WPLmU=Sa@JO>sP?Iv3MS->X_ zMAp=Gk-FH$7(}=` zPfqqeTw6LjIo34ivct$e$7D&|9Ch6BWB3!m^PoNGpMIj2&!w1#25!|~?Xf9v;`QQ( z5&P2F&Epl{T@lfrtc@#K9V}nmJ+5C7f_~n6sGTynWg#4k;1)}Cr%8L0(eKBz@3Kyf zisFd5XKX#Sh2&%W{IZTUH#$;lK{59;mfT!;+y&|4@r+!&m56>T(#I9ksKCvqC>3D& zd?a7hz)bL^U$hxBf!Fep{i~XW?cmSggeK*8T2RccmX{B23TN{17K5EHXEg*!l zb|}#vFb+d&IhjDak(v(ejGMIi(U?|xzqKsS`Hgp`CDk;3H8tR0z}@cnwB+GXpwy^= zOd>Anm+~&}aszHaH*1YhsusSJJ+hY>qoLO>9X7*QC94vlq0lB|2Q~TNLiCaHABA7N z>^QB31aF4n?!(>KmOb6zbvX+oI;bl@PnF&o#&$@#FPglq7ZZ`EeE2R_8tR64l{Vz` z(K;tE?_t<=r4!53r;$ri^()$jU@|6cAa>cr?2Qq7S8Rz1;~e*2Z!uh}m;m-&QG*gz z?C?W(H)-4p`%&HNiGjn1ft1L`F9v6k2E&oW1jqCnpAW9UbeAJJ^aZJ%av)1%NA(dX z4e^JGM&T2@Ji38~f$Bja2kh@f!sOHfLqaZi-xGC+9LlE4QFyRB@8fV)HRA_R|7@aa zRR#49kv(nt3vOpKU@J{yhq<4A`O#llg?UK`lE%7!akzBY1rOtV;%_YYBuIYAip*eu z0<@_v6Gv~F!^&M0Vxmo+F9kvHF7za-g>*Lm)Qn*99_9pFH5o-VzPBBte(1}IMs$1DR9cxXnK)2B)r1J4U-+69 zO$O0_3G_cm0@ zv~}32k7DSmm9^}8I+GxkBz%iFXk28H!N^3NyGN&ONbXf;<6z6#o9KOl4~;W7wzk}t z);3K~acY0)_7*nItA75<5v^CAR$%>YKyUl?cz6_rdi``0V%mC(^9vo)GsU=8vo&#D zF@$e>?v~}gq>=dhTavkzTk~RxDaK%+j_5s_j;N@#`{>NE{#7O@PRf-crPtc~D}Qju z_+2^XZ{Jg)y)Bj<;oqUs&Nu7rred+(?|+<*(6R)Yls(Nv7k7W?atG{i{gHgOIC0B# zBieTT6XMwHm*{PtXJ)D%x^;$o=jRe@pMHA%jTd#r zDi?>6-($1>oos~Ffo3$c{IaKfs_R@4x({n&J``T9y#DyoG5SGk^uw{CB!&5wK=7#> z%`=J3OWP1Ir*pOV^;_fq7Jl3@>M&aSj8+iWVu))!ofb2mX>RlFMCX}@JGlm7kigb) z@xt4kW7e_%u7_{uSa{nPQ#iO|;%;Sle(UWP3#enVqq-0Dz5IKWUvBV@K(M{_$;;cW zncPPwgzkfyl;aN}Q{K75=97MAqR=J5ySrOF#i3^(&Gj(H)+2KNJkg`XT1o``x=CdO z^17Vq;Bf>Gf))%6Q~ix&3xQdjJl3*a|84d-lJb~<@RpZQ9l6UF1e=(;T3cD}m*nn| zP;{p*yQdhCXWCm<$8Ac{*kfaCk&NtQBp)#>K*y#|QM}ZWPQN!XTbipF*7D#R5xNQ- zWDoiFwI&b{Px~-<^{EuhnttXVbY@~>b{R5OwN^x=uyaGxOYOOLY%=l}+3U;r)>|8; zrlx!Ck8xQ)L3NeuzEh!ycxUJ1&3rnoRvM{HHuE>2AsBX~!EuP@lmv;Zpqq30prA`h zw&sW3`2$LqSyW+9$!P!k_r76Z-pp(+lTe>tRhnYuDt!CEQS5 z2gN|t)y1?ZcFR7mxciU%1r2QyQg!}WvIVk~TvdszlZjDKT`tly)*ch)>66q&`r1Rz zCsiU{BGYIrX$sJZbjka73E0a49HuKd1{-G>bpX{aqO}z{sTR*S&h>3whWTPU>Wan$ z4i?01Q6u2mU$A$#b8QoAzTM1A-${ICP5V6(M1Q}LPlff(>)mW)OkGsqPyJ1dW~~Bt zh}&`fWpDbU9Ub03bX#QoqDlvP^aoYVN>3sI7aNX`J!2-4w=+A|4l?+OyaG}_e!!%j$4D&sOl1AMd&H>7o5kpHu{ zI+Ex4)rbfPI>`UW-lm_E(twOjyf#FLLwC#}dp@iq^iVXGVrvYvG?_Ra8UJ;NE8^Sc z!%Q2%!wm@Xr_sxt<@t{I~W z-@yDQ-Is$H+}QDOW~f*=dc4SyHil?a;rMA3lu9*5SrdbtU8kRb2Sl(dYeuLU|Cm}^ zk-44BJu*zHWk(K~aCPI1GN1f0#QTr9094|VAh%F z|Jf!g)@h7@A+WY%(G;oO% zr+AQ5TS$`m_lxP3mgH_B!~P(J_p0N-r@!1IUS*?=58PBkji>cZ6R7ELQ#q8dJZ|YV z8RrG1H0YTB(3DDRdWd|NeXc<~$narPl5+w{zvp@&c(6TSxd6p(76E#784!em!3v38 zpGDc?t4q72_z_RwHPSxq!H@eDgo--aeQ^7rw z+4K&%!)lX@E;36n5iVNhXI8DbB@FjP#Qmm227dcAi2$}ZH0&rbhm$^FM?-suE&J~o zRv60loQ4Q@0wCOdWlOo$DE=#^^aT2fJw_@-`vL`L4BnmeHKesv540gAg(8+`RpoUi zWZe&{7~Uwhq_Jp-ecbMRbW2nO?7a!#XCfaqI%iZvIw~$4*}P6u6AU;1PRUl*5j_PP z1-!g*PQQttq0Sb)B8uOvZ6yD{=2-(Gci7Kx*3eAqQ{JQ#kl3*db6PJ^VNoFU0t&@!nwmjjdT2qC29H3X?~XfAiHO zfm5c{q>vwC!z_06R6eDTi9Rdx08g|TqKkE*hhxoC#bOwxHAeKc1x4fbp;mZYUdKDo zol61?kw|`&Uct)QNqK!&S!(g;H|4|ByLi&yM2S{~Dn9+TpC-flkqqk{7tChC5xAlw zvQ`VMz1IZ=-qfL9YBw_ejE$xO?3gj04qWUw^Ql z{Lz~~Mx;vE`g+Sng91=Mdw|S^zRjuuEkWXIJ1c!j@X_}H%PV(RKsWYoWF#8|S`1^< zHOM=CrpKk{y)V}NVT>zfs*;7WG_a&){<9o=`Hx2!_(s@t<_d~gvOUQY3P1ZlWl0v- zt)Z{E176sCp2;wN#t+xzt{d}Bo7kSQLXcBV1YBfx<+8$4`DS?}Kl@ENxng_<0sQ>( z?Gm^;S-zSSjPjO6+h?dt$tYU2T%ZgSAg;|6vQN|uOIN54;X1PAICN8G&lB}}bj;ED8f zRnZ}>Nqodz87&ML8EIe5k2G@z*$7^Q=#-PS5=xq6&uUV#%x9h6Cb%z@XdckOZ#Er#W>qAjkB(&fK)bZV&!#B#S zGAhOI?N`u;0JWR18`0~_S7phJb91jA@67GddJkPtB zccO`+3YiKTc^bNfy831MhUJE)Ri;+8R<=#HPR&jp?H~{D9`BHWkf^ArgoK3j^z_`^ z+`^*5l9G}yU%s@ov~+iOM~z0sOvZqx!D$O=pTB)BST890UQ~HdS#?m=eAe9gtF!k{ z@9^;O^z`)N;^O!3-v_S;N1jHeUZ$2_mNs5D_V@RH{``6LdUW=Bc71()`+EEG@&d<3 zudlBg6(%4-1Oz$+6$M#+|BZ7~%iS*jbOCX4CUhd;gj_HBEvnU<*JMi4ayN&f$D zK>u?%Y8{FAaiOgcw{|I|E7##2E6#SHODCA4of};kgt_+p$owMfQ2(D`2tnORKwX6K zmUjply#U1u0^_3JNJ9*1Vol1$D2AI>`>0*dGFoKl4%gkU;Hx*SIiQUOhvS~mZ&!_B z5&~F1Y@H8}Hp_V01J$LQN*WZmK}VAL@+RiAJbm|ztYapJ4juko<9;V6$OkC_>&xhE{Xo{2QheSqcV2e}y1(pTyb5@b|RR0nm()kT7hk zJ}4a#O;D5r4UNyi{qY#d?#Eu;qNFL}C|aSJjHZ*d8{I_(PPD(8&_SWA`Ya2b{20~f zJy$1V1-a5ak;~ovxQFkkNpmUY#jMj*V{Bw!yQ26P;dx<>nLPC4`8c4TFvlVN=K5sF&b$JvO(42&rJ7Yl_!Sb{QVFb?NQQ~+>fevwBZv&I_C@!klFNmD)C~3-eL}-HII;JG@94Zkd~f*=33&6^n*-O#b~yyO zuiqdJ4blwuqYFdFhe5PCh7NY=w8RvlWn2rICcEfm;>|xMbWTa+W__&ZrOX{+;X=H@ zo+qWY+Saxf!=t!dCjq~#s0)uoM$LauT22m-O$;lFGqSKo919umwixcy>kQ4;v;2x1 zMZ-aNh?4GJ+2`tOw+cz8S*KpS0Pdwc5H03sN?EHtM*Iq`)&NbcmRR^xklV1XU5t?f zaJVN>h1(#BPlHRAQKpY_E$Y~Q<)Xs{RKEe-mHZ*`zfb@!6f9Cft7fxV$E_%6qP!1o z_o<^1-qbnbRXanpD^Lij+;B&?2@e(4GK*`axV)>f*bX@W1$9bnt%Drz6f_|0@O=|Os_X{w-Fhby*u12I6Ed;Wm;eV2{QtaXp<)$l^>8Y=K-{{(Yn z9abcP1Gm&?%wE1Y{>3XF@m1Eu;?KrtG#T`K2I7q9G0?oGl%C@9xrsK@(|*5khOB{# zcm8E`Ss+M6)3=H3rYWl-Vju(=9Hi1ww7^7(pE^>Zb(*aQet)p8K2%F!_T0su&i zmn3Ndy!%;V3kLf8vzpX#AwVRXY}I7NK&EjVJ?EjnJr=ta_9NSW*M^e-q&8$KiI*cm zN4#yt7Q0Jp6ug=hg^Zi|koIsCfE6}&q#5Zw2;rXN;On|85igx+Gqm8HBPEXJm)Po3 zTfk^4K(?0v+1h2G%6&J{IZ;uFf;WUKhFqUEh0Ucu?%Y*~uBe&Y0JG0XTvx&+BP+Pc-+W03QZE8WCr&qkr3U@#Z=RcievsF5wAh>^Y1Urk%HGr z34hzvQsdN1mqn(>oUeR8_a*S0F>U2v&%{4)j>=csHKIWrT6#9&92!=-yEGd8^lN`< zQ-RS{ZJ<%f-z=VoW|RNECU?)CKQg)EnzETu3ui<6uNfF!OQgjz6S+fj*<@)Y>&II1 zfh8+%!l$`im2g4BYwKXhI&M36X~)m^AP46=j7uUHLNj-zW2`CSgQlZ3N)+^p7PB`m zs+9ZjS(4N&31qd6<-PO8zW^ zvm&FQB=o5KJ%xrSc`GrFIo`xIB68Z-IiX|Wa-Q`I>+I*Z!E{|BQr1Dqs^W6?uOe_^ zN7qlEgF{7Bg_fjyEL}q+1kNi!Yo(DoO{{4xqR&XJ!fE`;Zy%HWT(G`9I{yWUk*Z={ zFLeF*v}u`$6rFCmiWKxRoKm`bZM_YLU$w|MjT8N4mYfw~R6Mm!KgoQ#zV7Qc7_acQ(*vFpxU1)Gk}cqGGm2-Pp8s+%)%Yc= zsRf;hRC(~tr*aJk8%(r%nz%MFbS_jX%+LL0#xL)2zcBXsw|l6h_X=N(bqWfP5!kU5 z6$L=3LYr_y5eo`=*}J^i0pSLRj5ZWLzg&HN2|THpqszd<`Q9v2*;HoH&xye1BII*_ z(I5>P2!bEHJb^+6R&Z2Mt;3<$EoP)4BW96Cqm%g9iWs4FG<4(+@QewD~?a~ zl|28hU@4QR)|GQV{+3HB@{6h0wX(ro024X*dCz?(Lh{bzY|Q=sLZ5|vD3p(dxuu$d zAq%lIoB$L3Al4mk6-QS%{L06EAZ~)|eJXDv$BgPKMOV@)g`9o+1n&)*c2jWQq`N+M z4?8(%t{-9b-}xzMbWw>p0x`YKlvsX8>mmmG(pZ8p*yd3~`rk`Usg!U=VP9crP3MxD z6eTeF+6x8iiVXcDp6)81WLOJrASo}_!UviVj7jmjuU{`6`#aAczY4hYwzquz#ztm9 ztA#y!V|H*z{mH}ri83tUn`Ocr{>ZvY*tb+Q?KkAMG#HmBpg&6VP%Am^Vk8*KNS&Ze z_NB~k^UhjUy4bAg@|Rr>PY_2V%ei=uQvQbl!8r99%I_7@47RW>UzP ztkALse$_)zS^*1g(z`_yV+?e{BNs#;s{Xj5;` z^Ab;NP*z~wC44e};4?(Cw1cbC@Yc&`a|~)5`s;@KdgC|D(EVY)T8IVjARi3ntbt$T zFGX|6C++oQ~Vm7v*scn>z|L3W6o1JNB4E_j@nsB#m`oI-$UE)>w7(UlH1 zV$RY>eqpZH96D$OhVG10IFJyARO#pWFLbHrrb}5F)q3TFl)RbCSrqy{Dnj^v^i%k%bBg;-8B|xOz=iD8Hxo9-9Bi(cDAF7BMvC{*kWvGQ! zP9cz}@5~HTvwZGjgtgLH$YA5?amq&kjutyQ;!GRLOnLZ2I?y}en_-nzmsC51JO@n` zw*l1v_mMErJuxM$mr27+y8o>ZNPX3l8mRuE#~q&2RQ*qL(D`=_>Z-^cD^4*sUQx%k zy?25y>Snju1DL~Mm9iJD^BYKhlOWFtm0X*boGhT|d(UX!uU?*@xZDUm%g95*Kg=A^ z?cPgpOwX$}6I7%#ODI+CnI%Kb2a)|PwEsC2r8No|q2#G@(%T+zq}zL`|MFgyJ9;%R z=_6}bQkt4$Q7RkM+h~$mn^EF}zbSkZ1V2uVU>D1J#_uksdd5$=YJs4O`#xcFB5K@% z#lRY5j3E9>AW|D5B(%Xb9%yBu{E>SLOJ$l?qSH%`wNYw-vv0 zoiB<*&V{1vVye{+(||{W&|nfvQ>jvwLJznuHvqe6Q%n2*I5+;TnyX@h2G2ojfn6l{ z+C2@VdCbuI6vMUwkbP?;uxrU)ALn7$ZapON8wK?qe|?JWWnF5CjST}k3+kvXuMBk| zBCRY+{i9uIxeMx;v=+VDz&j=J_-HZ?~178t_vMm#1Faj^3 zr=yb|f4_yH-Xr$=_C$t!2fO2q8nP9G1C9sP!6`j07*R%SNzvAzRvI%24iGJ+A z0k&^I5R$}2=eZO)J4~TJY?-fW?xZ`C-j{gRa2iLSWU~Az?$f2Rh0P%$k$%1Rc(CF= z6N|dK(2w8!9Prm&)$i)`kB^tf*$gL66Ic!D_m5VLljCC<5Fw6I94&5zd2id79TJ+U z)Z$DnnEInc3hjKOUfN6`uiz%>M|u+PQCuAWiByaX#kmL*BQ+zUnNTb}x!gWcs*0xwiJZN6Nu&cZxIC22ErBou9#was>l{|daZvA;K zpTR376nxz3f1~h*x&elwmrqy?J8aUQ`_z4lVo%8pS6S0AeSm4a=jm3gn=x83gwq-% zm!U@LR(7(u$VjIEjIr|T7;SfAoG!~Brdbk(bZR|1pG8^wLU zkwr*ek`5w)+k47XXD!f4n!L|$9h8;z0N}tCAccGGlFD}GBVAKd+9y-hM06)98xu54 zg8g^wZ74=rI@NHq0FK6cVtTt}Ge}ui{|Fv6OqdffF{&t-{}W+Y!Prv0cF}^BWh2zK zIBu$|x1bV(J;}`Nt!Tu#^qzNItdy3ZP__WpI_bQ#KgZf@N8xh{_=F1vUEBi>S;d%p zkXV=4t?;f43diF#^4~(w<|!&Cndb$ks@(Lf4+Q17S5_T1#njxS$v;_X4o7+f#C0t> zUb?9&`ikd!7%hiRh1MrRPKzLXN>OrPUr<);J`j#mbY0F^NO4r#~3}`DXG5 zz?Y-)tK_!=Y&aZ==Ns@0R5Uj}&RnC@JT6(_oo*Y46RWJ8xGGr)fvAN`MI5dtxJ3-M z_!WEu)*vdk*X5Bm2+_@?s>Lf}rf3$B#@|t(!fl@K&2IQOv$)C8g2pyCsWXM`(PHlu zc%RaKygd0H3w;#Y_JbteSR z7~nplGV)^g(~8v6)x!Gn$4Pkp;gSh(PTA=$HL-+?*M;y1Lq>--LVn_cQ4 ziyllwR5kf;6C+OMwhd;9C4_<|91_C-Jxf<>y9YnBtD)Y*z#;O7gwx~9g%Gtd^#G)j z_TLr zV7Zy{Ie&;+5ze75A1`%!3ns#WJ{(MRf)7(>Q`PeK`cn=GIaAdj^Ok3=$BVs9aPO-- z7OWT!jDSBM_#>?a^YezmGO&h-Q=%HS-0L&S?5R>^3lE__)_P>)<=l1rZzsyj?mmYq zf|Nr(b6iv01td8&soMv`aY_WLCuWIEF6-w%3J|r}$G;oh(L^J-3p)v0-JErz{6s zQ&{M)0=tAsk>KJL9Ald&h6xCJS;$;vd9)ud)`j&{0MAk@co?C_X|dICu<=4!ISJBL zP5elks<^bT@}@#FQ?2J7+~8LAZ&ggHG>=p(%~t;#uxraUjHu!_WxpWJqP}sDLOs(2 z-|Pyoi!Al8I_(KA`9rHeXjHermN-+bsD4U$qMRR-aUj2?y0N&`-{wf;+rBL47~d^4 zpr{+D7+Tr(yECMwiVLB`Y~UkUCahsQ_gN znNN8HXcMI-2BV$elf%6WBwi;cUiG8lf00Y4GWSZnMsyt=wCIcY{-5ds9qz5F1^+q( zgCACU@CjJ-68TQee$G+zQ$~_GW!E}d^h#4J0@2Vl^r91!!|gX00cN-HJ$g+)_W`_0 z_Qnt3X!`AX0s(pXO^H7gRd+~VL*{lLA;92Bms&>Vv_KBOSRDQN9zfX*skY!v5QMrJbDJZTz2%}g zNuGl%8I9bm07DkNb#_e^Y#4-^x&)81C8qqI@nL%u9BOaKKTMX3g_T(Zd->frNgfj3 zQebG{sC{!egTF`Xaw5t&=3#!!FGm|;!S^DwK zzV(Y_q;2q|aK;O#SF`^upDjfXGNzj$b90V~AhTMkyn}ZSp?eWIXPY(IjX7s381+=rxZpvQYk*6M~On>NmlPsC;3gqBa zh>*qR9I?5+@{N3Fl@4GMs6A}MY z{&2zqz?-{pP_aZyGhjvAcZb-`d-kmSZLqQtOZH|QO*L~zD~bOkT|m}e_G6Aqp(B%P zG?WR~(h|6069(Z`hDb4iQ86K7vyHLIP3)*K61-`$4%50+u9s7pI7#` z*9(nQadnRfEPx{%$Li`1q7dpb%8B#C?TJw;QV7JV7ACw9Q=e!m0-t1ArxRhwXvPs+ z-tSaVvuS93DQ79g6x~wwIJpd8_01|;Q>4t@vrWl+F8TEsrb5fbV2r*x@e0`c+3ed8 zcPbs7B@7soWkK}?kO&XWIyG3@C_J56ls`hmBJpq7=5Kc6@v@u*4R&6AJqxz~)qwQB z;Gr=>tq$$6Dj1uHe}6liHO^)%(kJRdstg}A{iM&!m45B-P@bD?8GwqJ?j$#0vC#i( zbmM&%je9AVa%dp(gA#mraA17rwXk9=5u%}i=#~sIT~UY}kfCE*N={X8ky=yAmQXQ-ugtk~V>heJdIR?3VNODu9&Pp=xg%_#lz z7qFY}GSJETknFWAcXhJZp)`2zn{^?#GF1T9ON7W=r zVY;{vf~;ulb$V`wqZe(NK#JgJn!Ajhii%bZ^G5i+{m)lBO9#a|T-!q7xmsb0P7o@U znxp2FErx2n0k2(F*ye%iVAsDarmw7%irOF;icQChGlHKuX!c4CM-?eM})&RY#FAflc6pvk7{egR8yu2a9HUlX-3it+q3CkF*aF9e0X&uJVO8|-?D}DxAp;8seOc1Vlu|R3q zqs&;K4x*d_ApT(^#cWpSvRJ7Mw~;f-Oa?Gw%^rYu5td;=DBSkUsKs4vdFDXzlM1GA ztmhTdl#Nj%-`Pd={-RkUauQ6 zXwf2Q0?;*8dYiZw_^LePe{4z;qk%^E3e7Rv6Vs4cE$(x8@W3UW@k4y_dA3xcf!$DK zMVWHdwQzX>z9I$QPIjoSc2r$Io^%NN2%iJi2WznURJNvyY7YQ9M&6Yecs~7ikx)b(bpBxcNqpc$ z86*GeWX)i+bX$V&ITpE=B}LsW1x^?ubHqSqGr{5r(|F=df9wh zw2k3tM=bX}n4yq<(LN7;qpL^-HC=Vqf?FYd(&-mEC`iKi%uvpyrV8lf<)X?9TaJ;T zmp&rI2aFPUTvl0lr_bRZ3K}D$osg2JxKq@v*t2c4eYo35uwedT-~u1kR>s- z23^`;aoa0pgVJFWJMlApaoC4L+>xegC>0EaN#v9KAKsCVFsAIedqW1OLTy^kHN{i? zGO)znxEM%S498#0Xfa$w;5<*2D+*N4cu*MP5w0F{MZ*l0KP~_w#mER{YUqE^6)JfE zFMdXnwU9uAF-d4+L_L7NDYy=Wum;D>XOSIsutseYgv2NpUXizQq&ic`gfFc1wv)v| zV=pO?u4VG|xsS*~-g~kqqyy))FHK!4C(Ca=caK{Atq??+p_f>}`>Cvs845Ho(6X@< z^1plExy5}%h}l5~aFF8?Q^Tv32uIQ0iTfx+tysB1hk%WW70!3PkNl5F0`hfqx#R!5 z$vjNsoD$LDUg_=}_Sm&OO6#wNQ-(RJEr5DKs6qojoRX8lfTv;chG-cU6#tyLCq8mt z{oq%Xid@Ms!knF8kt-xn-2?F}0CbAdfP+~C4qiRmyh^&` zfO)&ZtLk~}KjybX2Lrwv3{wcMZ2-qQ+sSf+V>u`m+?gjtEvZ(UfDR44FeR|aRa_EC zY?Yn~jDPZ7$p0uH#gmYeycBSn>OaA;4fm)4B2C&eS!hp%5puzi`1N6%sah62Ty5Yh zJ(hEys>BP+(<_+5U4@KwgGsYk)z8X_&`F8G_y)fJp&e}ybbfBQAaC{;Nq$A0#K}6fF zMAx-gPTu%);7T)OFMx$+&#ea_FYLS`h0@lQnwkVOoJ+M>K~ioP>d$-J-%9v?t|FDv zHkNP{gra!u!V4A?wOR35Wf*@GC(E-cM>yD_!{Lx&P=!m+FL^zj1AJ#^coJMO;>=8L zG{a0Gisk6yq&kTN|5Iq~Y|6c5jVf$;v8TP+nftsk9A(xaZoZ0j%>J?##-zVQW>7Ig zRCCHt=J0OK@~QFIvmXOiIr3dv*;pcO6Va1(9D`vCD%kdXAi!m&_M5HD@k*{wSR6_l zaI`oHiuy)+lf{8OfmA97TUOO5{FkE!fi+qSP~s{z_n&CaFiT|q#}T9HaTkZj_jcHS zri{Vy9Dh#-ifP-A4cL zv2tl&vfdD_buC=F+_U;+Tw=U?{;^7b|EwWAWdmOk$3(|sIV7mWvT(icEaJ~&P)jAQA&*8Q|3|ioqvld<579%yjvO_L)IG9SiC-Yl-=D>~Sxt7~gPl154iDwCqT~teTsckDmg_F`LkvjI^iXa8wR;jbOuLa=1I7*9M-> zv=zPqa=@CNSF-wd>P`dNNyLM)V?y*oS^uIA_s~84aZF`&>t8lmmYs>wf~oDZyGCB@ z_HU&7j&c!|SjdNsEIu|3)JK-FgRXDtTK~(jor(V@2D^);>ipVtsj*LA&v;kS!XC#$ znt`fl1Vgzu99^YGV}z%Wb?L@xoEpV~S%T`Bp2XXdqhtg3Ppe^i{c3%4bR55Dvg*6j zujv;raQEJ?6OVOmYRdlLEG2<2A5OdUg&`eG!b9Jd?WMaG@@PT#6i5WwEeUn{Z^Qt7 z@a$*FU@2bzF2Ht}00LSDE?QL%)(Tqm?_R1RS(2Ckv-`S7p35}CASAKk*6a)DmcwE{-aAx0rOfJi_FeT{TA!e*+gS{O>g;bLLv9(ycSE(^5GP*D~(>|X2v zuh91SB)~_6bo+Pf=Mc!ondg(%^-*C=GkkrLpM3x0&Cwg^0~Y+`xRaP30A@K-pW=aM zYhtD9+#`J%Bq9$5N=Jmd=;N_FclkFI=X6kiB&1u=)(r*Tls%h@Ok{9O(XEc6=Kr%j zVx6h4;vYY_ksqqHSZdQ^e@T0tPaE^+_wZ~fe8l{%NMu^BPxtj*v%C}Z4Rz(Z%(M9? zX|8?#^AgAYcUNMVl%51UKQKdj@4n9Phumj3>4b^Kuz?C;cO92AN7DT-KWc5CZ}*?U z1-M-0iC=nkOMTiBz8@jem%dyLEZRTUZ8p)p_k6#M)5U~08aqXfXZQ*EF6Hc3;R&8< zI{lTdiObKP`}g+zKVNQi>CwV@hIbvUVt(GsGnn-3z|X5OOpA1zmmK}=J>Xf^v$jUN63orDoflrV`P)7$Is(uI=z9%VBeGK=Z`Jt8(y0` zFZK6HE9XVb`dZT~jx2L|rtzd``N`~+A%b1ovim1_?R)MWl{yF5=rJ+dDn3taJ#V8E z!w(~=N0%Qp9%oHHUphgEE2ORB-x5!QLk04arnP+8toiP5kAsGWnd^B&OXoz^v_l&l z4gM)Fs(p24X4n?CnRZwGZvAIwxRl#tvs0o3wAsVc)z4*}Q$iE!9?YvcC6GOsK6;SD zG!7U@PoAqMGTDJiaFQV#{M?OK`qGROCkHYL15e-J(PU&2VSpdgfwGrG0%R2&oCNDg zG=QAf0W#x1SY#F>@n)D$KA^7--X!SON z6ANS}@79Cp2bn0!G+BaCK^S5HbZcrPc+=`+VMBd+;3*-ITfS#pVg+usXa;Vz;DLJ% z#E_qyXebR= BASE_ADDRESS) & (adr_i < BASE_ADDRESS + SIZE); + + wire [13:0] memory_address = (adr_i - BASE_ADDRESS) >> 2; + +memory_ice40_spram memory( + .clk(clk_i), + .rst(rst_i), + .chip_select(stb_i & cyc_i & !ack_o & addressed), + .wen(we_i), + .wmask(sel_i), + .addr(memory_address), + .wdata(dat_i), + .rdata(data)); + + always @(posedge clk_i) begin + ack_o <= 0; + err_o <= 0; + rty_o <= 0; + + if (stb_i & cyc_i & !ack_o & addressed) begin + ack_o <= 1; + end + end + + +endmodule From 3cc8e22ab1a2891ca27e91a27f0fa0eab2338a85 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 2 Sep 2024 23:01:54 +0100 Subject: [PATCH 18/88] update linker script --- freertos/app/crush.ld | 25 ++++++++++--------------- freertos/app/src/start.c | 26 ++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/freertos/app/crush.ld b/freertos/app/crush.ld index c9ac79e..6ebedbd 100644 --- a/freertos/app/crush.ld +++ b/freertos/app/crush.ld @@ -3,31 +3,26 @@ ENTRY(start) MEMORY { - ram (rwx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 - - /* TODO move firmware to the flash, set up load from flash to program memory */ - /* - * TODO would be even better if we move the RAM to SPRAM too next to the - * firmware and stop using blockram. - */ - /* - ram (rw): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 - program (rx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 - flash (r): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 - */ + flash (r): ORIGIN = 0x10000000, LENGTH = 0x8000 + ram (rw): ORIGIN = 0x20000000, LENGTH = 0x8000 + program (rx): ORIGIN = 0x20008000, LENGTH = 0x8000 } SECTIONS { - /* TODO move firmware to the program memory, set up load from flash to program memory */ - .ram : { + .program : { . = ALIGN(4); + __program_start = .; KEEP(*(.start)) *(.text .text.*) *(.rodata .rodata*) . = ALIGN(4); *(.data .data.*); - } > ram + __program_end = .; + } > program AT> flash + + __flash_start = LOADADDR(.program); + __flash_end = LOADADDR(.program) + LENGTH(.program); .bss (NOLOAD) : { . = ALIGN(4); diff --git a/freertos/app/src/start.c b/freertos/app/src/start.c index 8be6d5b..4e3552f 100644 --- a/freertos/app/src/start.c +++ b/freertos/app/src/start.c @@ -8,9 +8,19 @@ */ /** The start of the region in RAM to be zero initialised */ -int bss_start[0]; +extern int bss_start[0]; /** The end of the region in RAM to be zero initialised */ -int bss_end[0]; +extern int bss_end[0]; + +/** The start of the region in flash containing the program */ +extern int __flash_start[0]; +/** The end of the region in flash containing the program */ +extern int __flash_end[0]; + +/** The start of the region in RAM where program is copied and executed from */ +extern int __program_start[0]; +/** The end of the region in RAM where program is copied and executed from */ +extern int __program_end[0]; /** * @} @@ -26,6 +36,18 @@ int main(void); */ void c_start(void) { + { + int *src = __flash_start; + int *dst = __program_start; + + while(src < __flash_end) { + *dst = *src; + + dst++; + src++; + } + } + for(int *i = bss_start; i < bss_end; i++) { *i = 0; From 715d76fbca51c769f6a38c7fef7c3e472a7053c1 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 2 Sep 2024 23:53:05 +0100 Subject: [PATCH 19/88] set up simulation for freertos --- crush.core | 1 + .../freertos_config/include/FreeRTOSConfig.h | 4 +- rtl/cpu/cpu.v | 5 +- rtl/cpu/mtimer.v | 2 +- rtl/soc/memory_ice40_spram_wb.v | 2 +- run_sim.sh | 1 + sim/cpu.v | 59 +++++++++++++------ tools/cpu2.gtkw | 50 ++++++++++++++++ 8 files changed, 100 insertions(+), 24 deletions(-) create mode 100755 run_sim.sh create mode 100644 tools/cpu2.gtkw diff --git a/crush.core b/crush.core index e51179a..d0cc014 100644 --- a/crush.core +++ b/crush.core @@ -18,6 +18,7 @@ filesets: - rtl/soc/memory.v - rtl/soc/memory_infer.v: {file_type: systemVerilogSource} - rtl/soc/memory_ice40_spram.v + - rtl/soc/memory_ice40_spram_wb.v - rtl/soc/top.v - rtl/soc/gpio.v - fw/binary/crush-blinky.data: diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h index c2cc05d..41dd526 100644 --- a/freertos/app/freertos_config/include/FreeRTOSConfig.h +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -435,7 +435,7 @@ #define INCLUDE_xTaskGetHandle 0 #define INCLUDE_xTaskResumeFromISR 0 -#define configMTIME_BASE_ADDRESS 0 -#define configMTIMECMP_BASE_ADDRESS 0 +#define configMTIME_BASE_ADDRESS 0x30000000 +#define configMTIMECMP_BASE_ADDRESS 0x30000008 #endif /* FREERTOS_CONFIG_H */ diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index 0c8e9fc..a0d2df9 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -44,9 +44,10 @@ reg[31:0] pc_value; wire[31:0] pc; wire[31:0] pc_inc; -reg [31:0] mstatus; -reg [31:0] mepc; reg [31:0] mcause; +reg [31:0] mepc; +reg [31:0] mie; +reg [31:0] mstatus; wire mstatus_mie = mstatus[3]; diff --git a/rtl/cpu/mtimer.v b/rtl/cpu/mtimer.v index 572de4f..76a06bf 100644 --- a/rtl/cpu/mtimer.v +++ b/rtl/cpu/mtimer.v @@ -11,7 +11,7 @@ module mtimer #( input wire [31:0] adr_i, input wire [3:0] sel_i, input wire [31:0] dat_i, - output reg [31:0] dat_o, + output wire [31:0] dat_o, input wire we_i, output reg ack_o, output reg err_o, diff --git a/rtl/soc/memory_ice40_spram_wb.v b/rtl/soc/memory_ice40_spram_wb.v index 9915397..641d470 100644 --- a/rtl/soc/memory_ice40_spram_wb.v +++ b/rtl/soc/memory_ice40_spram_wb.v @@ -18,7 +18,7 @@ module memory_ice40_spram_wb #( output reg rty_o ); - localparam SIZE = 16384; + localparam SIZE = 65536; reg [31:0] data; assign dat_o = ack_o ? data : 32'hzzzz_zzzz; diff --git a/run_sim.sh b/run_sim.sh new file mode 100755 index 0000000..6e99d53 --- /dev/null +++ b/run_sim.sh @@ -0,0 +1 @@ +fusesoc run --target sim_cpu --build --resolve-env-vars-early crush && vvp -n build/crush_0.0.1/sim_cpu-icarus/crush_0.0.1 +BINARY_PATH=freertos/app/build/crush_freertos.data diff --git a/sim/cpu.v b/sim/cpu.v index 096dd2d..3744005 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -5,7 +5,7 @@ `default_nettype none -`timescale 1s/1s +`timescale 1ns/1ps module cpu_tb; @@ -24,7 +24,7 @@ wire ack_i; wire err_i = 0; wire rty_i = 0; -cpu #(.INITIAL_PC('h1000_0000)) dut ( +cpu #(.INITIAL_PC('h2000_8000)) dut ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), @@ -40,7 +40,7 @@ cpu #(.INITIAL_PC('h1000_0000)) dut ( ); wire flash_ack_o; -flash_emulator #(.BASE_ADDRESS('h1000_0000), .SIZE('h20_0000)) flash_emulator ( +flash_emulator #(.BASE_ADDRESS('h1000_0000), .SIZE('h1_0000)) flash_emulator ( .clk_i(clk), .rst_i(reset), .stb_i(stb_o), @@ -56,7 +56,7 @@ flash_emulator #(.BASE_ADDRESS('h1000_0000), .SIZE('h20_0000)) flash_emulator ( ); wire memory_ack_o; -sim_memory #(.BASE_ADDRESS('h2000_0000), .SIZE('h4000)) memory ( +memory_ice40_spram_wb #(.BASE_ADDRESS('h2000_0000)) memory ( .clk_i(clk), .rst_i(reset), .stb_i(stb_o), @@ -71,12 +71,8 @@ sim_memory #(.BASE_ADDRESS('h2000_0000), .SIZE('h4000)) memory ( .rty_o(rty_i) ); -wire control_ack_o; -control #( - .BASE_ADDRESS('h3000_0000), - .MEMORY_BASE_ADDRESS('h2000_0000), - .MEMORY_SIZE('h4000) -) control ( +wire mtimer_ack_o; +mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( .clk_i(clk), .rst_i(reset), .stb_i(stb_o), @@ -86,28 +82,55 @@ control #( .dat_i(dat_o), .dat_o(dat_i), .we_i(we_o), - .ack_o(control_ack_o), + .ack_o(mtimer_ack_o), .err_o(err_i), - .rty_o(rty_i), - .memory(memory.mem) + .rty_o(rty_i) ); -assign ack_i = flash_ack_o | memory_ack_o | control_ack_o; +wire gpio_ack_o; +wire gpio_rty_o; +wire gpio_err_o; +wire [5:0] unused; +reg btn = 0; +reg led1; +reg led2; +gpio #(.BASE_ADDRESS('h4000_0000)) gpio ( + .clk_i(clk), + .rst_i(reset), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(gpio_ack_o), + .err_o(gpio_err_o), + .rty_o(gpio_rty_o), + .pin_input({{7{1'b0}}, btn}), + .pin_output({unused, led2, led1}) +); + +assign ack_i = flash_ack_o | memory_ack_o | mtimer_ack_o | gpio_ack_o; + +always begin + #42 clk <= !clk; +end always begin - #0.5 clk <= !clk; + #1000 btn <= !btn; end initial begin $dumpfile("cpu.vcd"); $dumpvars(0); - #2.5 reset = 0; - #0.5 + #250 reset = 0; + #50 #300_000 - $error("Stop was not called within 300k clock cycles, stopping now"); + $error("Stop was not called within 300 us, stopping now"); $fatal; end diff --git a/tools/cpu2.gtkw b/tools/cpu2.gtkw new file mode 100644 index 0000000..74dab8f --- /dev/null +++ b/tools/cpu2.gtkw @@ -0,0 +1,50 @@ +[*] +[*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI +[*] Mon Sep 2 22:39:15 2024 +[*] +[dumpfile] "/home/barabas/data3/projects/hardware/risc-v/cpu.vcd" +[dumpfile_mtime] "Mon Sep 2 22:32:59 2024" +[dumpfile_size] 38412 +[savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/cpu2.gtkw" +[timestart] 0 +[size] 1910 1001 +[pos] -1 -1 +*-19.421982 235000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] cpu_tb. +[sst_width] 318 +[signals_width] 291 +[sst_expanded] 1 +[sst_vpaned_height] 296 +@28 +cpu_tb.clk[0] +cpu_tb.reset[0] +@200 +-wishbone +@28 +cpu_tb.stb_o[0] +cpu_tb.cyc_o[0] +@22 +cpu_tb.sel_o[3:0] +cpu_tb.adr_o[31:0] +@28 +cpu_tb.we_o[0] +@22 +cpu_tb.dat_o[31:0] +cpu_tb.dat_i[31:0] +@28 +cpu_tb.ack_i[0] +cpu_tb.err_i[0] +cpu_tb.rty_i[0] +@200 +-GPIO +@28 +cpu_tb.btn[0] +cpu_tb.led1[0] +cpu_tb.led2[0] +@200 +-mtimer +@22 +cpu_tb.mtimer.mtime[63:0] +cpu_tb.mtimer.mtimecmp[63:0] +[pattern_trace] 1 +[pattern_trace] 0 From e8a42247105c0740dc55eedbb8e05d745ed89126 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 4 Sep 2024 20:57:11 +0100 Subject: [PATCH 20/88] run program from flash --- freertos/app/crush.ld | 22 +++++++++++-------- freertos/app/src/start.c | 22 +++++++++---------- run_sim.sh | 3 ++- sim/cpu.v | 6 ++--- tools/cpu2.gtkw | 47 +++++++++++++++++++++++++++++++++++----- 5 files changed, 71 insertions(+), 29 deletions(-) diff --git a/freertos/app/crush.ld b/freertos/app/crush.ld index 6ebedbd..557fe34 100644 --- a/freertos/app/crush.ld +++ b/freertos/app/crush.ld @@ -3,26 +3,30 @@ ENTRY(start) MEMORY { - flash (r): ORIGIN = 0x10000000, LENGTH = 0x8000 - ram (rw): ORIGIN = 0x20000000, LENGTH = 0x8000 - program (rx): ORIGIN = 0x20008000, LENGTH = 0x8000 + flash (rx): ORIGIN = 0x10000000, LENGTH = 0x10000 + ram (rwx): ORIGIN = 0x20000000, LENGTH = 0x10000 } SECTIONS { - .program : { + .flash : { . = ALIGN(4); - __program_start = .; KEEP(*(.start)) *(.text .text.*) *(.rodata .rodata*) . = ALIGN(4); + } > flash + + .data : { + . = ALIGN(4); + __data_start = .; *(.data .data.*); - __program_end = .; - } > program AT> flash + . = ALIGN(4); + __data_end = .; + } > ram AT> flash - __flash_start = LOADADDR(.program); - __flash_end = LOADADDR(.program) + LENGTH(.program); + __flash_data_start = LOADADDR(.data); + __flash_data_end = LOADADDR(.data) + LENGTH(.data); .bss (NOLOAD) : { . = ALIGN(4); diff --git a/freertos/app/src/start.c b/freertos/app/src/start.c index 4e3552f..16e36a8 100644 --- a/freertos/app/src/start.c +++ b/freertos/app/src/start.c @@ -12,15 +12,15 @@ extern int bss_start[0]; /** The end of the region in RAM to be zero initialised */ extern int bss_end[0]; -/** The start of the region in flash containing the program */ -extern int __flash_start[0]; -/** The end of the region in flash containing the program */ -extern int __flash_end[0]; +/** The start of the region in flash containing the program data */ +extern int __flash_data_start[0]; +/** The end of the region in flash containing the program data */ +extern int __flash_data_end[0]; -/** The start of the region in RAM where program is copied and executed from */ -extern int __program_start[0]; -/** The end of the region in RAM where program is copied and executed from */ -extern int __program_end[0]; +/** The start of the region in RAM where program data is copied */ +extern int __data_start[0]; +/** The end of the region in RAM where program data is copied*/ +extern int __data_end[0]; /** * @} @@ -37,10 +37,10 @@ int main(void); void c_start(void) { { - int *src = __flash_start; - int *dst = __program_start; + int *src = __flash_data_start; + int *dst = __data_start; - while(src < __flash_end) { + while(src < __flash_data_end) { *dst = *src; dst++; diff --git a/run_sim.sh b/run_sim.sh index 6e99d53..2857cf6 100755 --- a/run_sim.sh +++ b/run_sim.sh @@ -1 +1,2 @@ -fusesoc run --target sim_cpu --build --resolve-env-vars-early crush && vvp -n build/crush_0.0.1/sim_cpu-icarus/crush_0.0.1 +BINARY_PATH=freertos/app/build/crush_freertos.data +cmake --build ./freertos/app/build +fusesoc run --target sim_cpu --build --resolve-env-vars-early crush && vvp -n build/crush_0.0.1/sim_cpu-icarus/crush_0.0.1 +BINARY_PATH=freertos/app/build/crush_freertos.bin diff --git a/sim/cpu.v b/sim/cpu.v index 3744005..86cd1e3 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -24,7 +24,7 @@ wire ack_i; wire err_i = 0; wire rty_i = 0; -cpu #(.INITIAL_PC('h2000_8000)) dut ( +cpu #(.INITIAL_PC('h1000_0000)) dut ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), @@ -128,9 +128,9 @@ initial begin #250 reset = 0; #50 - #300_000 + #30_000_000 - $error("Stop was not called within 300 us, stopping now"); + $error("Stop was not called within 30 ms, stopping now"); $fatal; end diff --git a/tools/cpu2.gtkw b/tools/cpu2.gtkw index 74dab8f..d9ef03d 100644 --- a/tools/cpu2.gtkw +++ b/tools/cpu2.gtkw @@ -1,16 +1,17 @@ [*] [*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI -[*] Mon Sep 2 22:39:15 2024 +[*] Wed Sep 4 19:37:11 2024 [*] [dumpfile] "/home/barabas/data3/projects/hardware/risc-v/cpu.vcd" -[dumpfile_mtime] "Mon Sep 2 22:32:59 2024" -[dumpfile_size] 38412 +[dumpfile_mtime] "Wed Sep 4 19:34:41 2024" +[dumpfile_size] 10598309 [savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/cpu2.gtkw" -[timestart] 0 +[timestart] 5748817000 [size] 1910 1001 [pos] -1 -1 -*-19.421982 235000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-19.421982 5751060000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] cpu_tb. +[treeopen] cpu_tb.dut. [sst_width] 318 [signals_width] 291 [sst_expanded] 1 @@ -30,12 +31,48 @@ cpu_tb.adr_o[31:0] cpu_tb.we_o[0] @22 cpu_tb.dat_o[31:0] +@23 cpu_tb.dat_i[31:0] @28 cpu_tb.ack_i[0] cpu_tb.err_i[0] cpu_tb.rty_i[0] @200 +-CPU +@22 +cpu_tb.dut.pc[31:0] +cpu_tb.dut.registers.x0[31:0] +cpu_tb.dut.registers.x1[31:0] +cpu_tb.dut.registers.x2[31:0] +cpu_tb.dut.registers.x3[31:0] +cpu_tb.dut.registers.x4[31:0] +cpu_tb.dut.registers.x5[31:0] +cpu_tb.dut.registers.x6[31:0] +cpu_tb.dut.registers.x7[31:0] +cpu_tb.dut.registers.x8[31:0] +cpu_tb.dut.registers.x9[31:0] +cpu_tb.dut.registers.x11[31:0] +cpu_tb.dut.registers.x12[31:0] +cpu_tb.dut.registers.x13[31:0] +cpu_tb.dut.registers.x14[31:0] +cpu_tb.dut.registers.x15[31:0] +cpu_tb.dut.registers.x16[31:0] +cpu_tb.dut.registers.x17[31:0] +cpu_tb.dut.registers.x18[31:0] +cpu_tb.dut.registers.x19[31:0] +cpu_tb.dut.registers.x20[31:0] +cpu_tb.dut.registers.x21[31:0] +cpu_tb.dut.registers.x22[31:0] +cpu_tb.dut.registers.x23[31:0] +cpu_tb.dut.registers.x24[31:0] +cpu_tb.dut.registers.x25[31:0] +cpu_tb.dut.registers.x26[31:0] +cpu_tb.dut.registers.x27[31:0] +cpu_tb.dut.registers.x28[31:0] +cpu_tb.dut.registers.x29[31:0] +cpu_tb.dut.registers.x30[31:0] +cpu_tb.dut.registers.x31[31:0] +@200 -GPIO @28 cpu_tb.btn[0] From 823354ea8f77c26b1b3935febc92e2c543a1b58a Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 4 Sep 2024 21:22:28 +0100 Subject: [PATCH 21/88] Fix errors in string.c --- freertos/app/freertos_config/string.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/freertos/app/freertos_config/string.c b/freertos/app/freertos_config/string.c index 7b7b6b5..cbc3b97 100644 --- a/freertos/app/freertos_config/string.c +++ b/freertos/app/freertos_config/string.c @@ -12,17 +12,21 @@ void* memcpy( void *restrict a_dest, const void *restrict a_src, size_t count ) char *dest = a_dest; const char *src = a_src; - for(int i = 0; i < count; i++) { + for(size_t i = 0; i < count; i++) { dest[i] = src[i]; } + + return dest; } void *memset( void *a_dest, int ch, size_t count ) { char *dest = a_dest; - for(int i = 0; i < count; i++) { + for(size_t i = 0; i < count; i++) { dest[i] = ch; } + + return dest; } int memcmp( const void* a_lhs, const void* a_rhs, size_t count ) { From 30b23edc8e865fa6d8ef0aa78f386f83383efa97 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 4 Sep 2024 23:00:46 +0100 Subject: [PATCH 22/88] Fix recursive standard library functions --- freertos/app/freertos_config/CMakeLists.txt | 14 ++++++++++--- tools/cpu2.gtkw | 23 +++++++++++++-------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/freertos/app/freertos_config/CMakeLists.txt b/freertos/app/freertos_config/CMakeLists.txt index 4f5900c..316e474 100644 --- a/freertos/app/freertos_config/CMakeLists.txt +++ b/freertos/app/freertos_config/CMakeLists.txt @@ -7,6 +7,14 @@ target_compile_definitions(freertos_config PUBLIC projCOVERAGE_TEST=0) target_sources(freertos_config PRIVATE string.c) -# options for cross-compilation or something like that? -target_compile_definitions(freertos_config PUBLIC ${definitions}) -target_compile_options(freertos_config PUBLIC ${options}) +# When compiling our memset implementation, this optimisation inserts a +# recursive call. +# +# Disable it for this module only. We want other places to call this memset, so +# that we can optimise the implementation once here and get the speed benefits +# everywhere else. +# +# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-ftree-loop-distribute-patterns +# +# https://stackoverflow.com/a/33818680/15158846 +target_compile_options(freertos_config PRIVATE "-fno-tree-loop-distribute-patterns") diff --git a/tools/cpu2.gtkw b/tools/cpu2.gtkw index d9ef03d..d3c149c 100644 --- a/tools/cpu2.gtkw +++ b/tools/cpu2.gtkw @@ -1,19 +1,19 @@ [*] [*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI -[*] Wed Sep 4 19:37:11 2024 +[*] Wed Sep 4 20:55:14 2024 [*] [dumpfile] "/home/barabas/data3/projects/hardware/risc-v/cpu.vcd" -[dumpfile_mtime] "Wed Sep 4 19:34:41 2024" -[dumpfile_size] 10598309 +[dumpfile_mtime] "Wed Sep 4 20:28:03 2024" +[dumpfile_size] 9421366 [savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/cpu2.gtkw" -[timestart] 5748817000 +[timestart] 0 [size] 1910 1001 [pos] -1 -1 -*-19.421982 5751060000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-32.421982 1460088000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] cpu_tb. [treeopen] cpu_tb.dut. -[sst_width] 318 -[signals_width] 291 +[sst_width] 273 +[signals_width] 278 [sst_expanded] 1 [sst_vpaned_height] 296 @28 @@ -31,7 +31,6 @@ cpu_tb.adr_o[31:0] cpu_tb.we_o[0] @22 cpu_tb.dat_o[31:0] -@23 cpu_tb.dat_i[31:0] @28 cpu_tb.ack_i[0] @@ -39,8 +38,13 @@ cpu_tb.err_i[0] cpu_tb.rty_i[0] @200 -CPU -@22 +@2028 +^1 /home/barabas/data3/projects/hardware/risc-v/tools/cpu_state_filter.txt +cpu_tb.dut.state[2:0] +@23 cpu_tb.dut.pc[31:0] +@22 +cpu_tb.dut.instruction[31:0] cpu_tb.dut.registers.x0[31:0] cpu_tb.dut.registers.x1[31:0] cpu_tb.dut.registers.x2[31:0] @@ -51,6 +55,7 @@ cpu_tb.dut.registers.x6[31:0] cpu_tb.dut.registers.x7[31:0] cpu_tb.dut.registers.x8[31:0] cpu_tb.dut.registers.x9[31:0] +cpu_tb.dut.registers.x10[31:0] cpu_tb.dut.registers.x11[31:0] cpu_tb.dut.registers.x12[31:0] cpu_tb.dut.registers.x13[31:0] From 0ca5ca7357902ed241195efaaeb66b9555cddd97 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 4 Sep 2024 23:21:16 +0100 Subject: [PATCH 23/88] Fix C runtime initialisation --- freertos/app/crush.ld | 7 +++---- freertos/app/src/start.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/freertos/app/crush.ld b/freertos/app/crush.ld index 557fe34..2f3e841 100644 --- a/freertos/app/crush.ld +++ b/freertos/app/crush.ld @@ -13,25 +13,24 @@ SECTIONS . = ALIGN(4); KEEP(*(.start)) *(.text .text.*) - *(.rodata .rodata*) + *(.rodata .rodata* .srodata .srodata.*) . = ALIGN(4); } > flash .data : { . = ALIGN(4); __data_start = .; - *(.data .data.*); + *(.data .data.* .sdata .sdata.*); . = ALIGN(4); __data_end = .; } > ram AT> flash __flash_data_start = LOADADDR(.data); - __flash_data_end = LOADADDR(.data) + LENGTH(.data); .bss (NOLOAD) : { . = ALIGN(4); bss_start = .; - *(.bss .bss.*) + *(.bss .bss.* .sbss .sbss.*) *(COMMON) . = ALIGN(4); bss_end = .; diff --git a/freertos/app/src/start.c b/freertos/app/src/start.c index 16e36a8..20f99ee 100644 --- a/freertos/app/src/start.c +++ b/freertos/app/src/start.c @@ -40,7 +40,7 @@ void c_start(void) int *src = __flash_data_start; int *dst = __data_start; - while(src < __flash_data_end) { + while(dst < __data_end) { *dst = *src; dst++; From 9d0bb4580b6c1cfe7873758c755c8f65423bff01 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 4 Sep 2024 23:43:38 +0100 Subject: [PATCH 24/88] Update simulation timings --- .../app/freertos_config/include/FreeRTOSConfig.h | 2 +- freertos/app/src/hal.c | 2 +- sim/cpu.v | 6 +++--- tools/cpu2.gtkw | 16 ++++++++++------ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h index 41dd526..be2b106 100644 --- a/freertos/app/freertos_config/include/FreeRTOSConfig.h +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -51,7 +51,7 @@ * The default value is set to 20MHz and matches the QEMU demo settings. Your * application will certainly need a different value so set this correctly. * This is very often, but not always, equal to the main system clock frequency. */ -#define configCPU_CLOCK_HZ ( ( unsigned long ) 20000000 ) +#define configCPU_CLOCK_HZ ( ( unsigned long ) 12000000 ) /******************************************************************************/ /* Scheduling behaviour related definitions. **********************************/ diff --git a/freertos/app/src/hal.c b/freertos/app/src/hal.c index b2269fc..609b63c 100644 --- a/freertos/app/src/hal.c +++ b/freertos/app/src/hal.c @@ -4,7 +4,7 @@ void delay() { - vTaskDelay(pdMS_TO_TICKS(1000)); + vTaskDelay(pdMS_TO_TICKS(50)); } #define GPIO_BASE_ADDRESS ((int *)0x40000000) diff --git a/sim/cpu.v b/sim/cpu.v index 86cd1e3..db7cbe9 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -118,7 +118,7 @@ always begin end always begin - #1000 btn <= !btn; + #50_000_000 btn <= !btn; end initial begin @@ -128,9 +128,9 @@ initial begin #250 reset = 0; #50 - #30_000_000 + #300_000_000 - $error("Stop was not called within 30 ms, stopping now"); + $error("Stop was not called within 300 ms, stopping now"); $fatal; end diff --git a/tools/cpu2.gtkw b/tools/cpu2.gtkw index d3c149c..1d57e30 100644 --- a/tools/cpu2.gtkw +++ b/tools/cpu2.gtkw @@ -1,15 +1,15 @@ [*] [*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI -[*] Wed Sep 4 20:55:14 2024 +[*] Wed Sep 4 22:23:38 2024 [*] [dumpfile] "/home/barabas/data3/projects/hardware/risc-v/cpu.vcd" -[dumpfile_mtime] "Wed Sep 4 20:28:03 2024" -[dumpfile_size] 9421366 +[dumpfile_mtime] "Wed Sep 4 22:20:59 2024" +[dumpfile_size] 45274152 [savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/cpu2.gtkw" [timestart] 0 [size] 1910 1001 [pos] -1 -1 -*-32.421982 1460088000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-32.421982 2990000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] cpu_tb. [treeopen] cpu_tb.dut. [sst_width] 273 @@ -41,9 +41,8 @@ cpu_tb.rty_i[0] @2028 ^1 /home/barabas/data3/projects/hardware/risc-v/tools/cpu_state_filter.txt cpu_tb.dut.state[2:0] -@23 -cpu_tb.dut.pc[31:0] @22 +cpu_tb.dut.pc[31:0] cpu_tb.dut.instruction[31:0] cpu_tb.dut.registers.x0[31:0] cpu_tb.dut.registers.x1[31:0] @@ -88,5 +87,10 @@ cpu_tb.led2[0] @22 cpu_tb.mtimer.mtime[63:0] cpu_tb.mtimer.mtimecmp[63:0] +@28 +cpu_tb.mtimer.ack_o[0] +cpu_tb.mtimer.interrupt_enable[0] +@29 +cpu_tb.mtimer.interrupt[0] [pattern_trace] 1 [pattern_trace] 0 From eba277c0e9bc073d1576907de0518c8765f79cec Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 5 Sep 2024 21:42:30 +0100 Subject: [PATCH 25/88] connect interrupt signals to mtimer --- rtl/cpu/cpu.v | 8 ++++++-- sim/cpu.v | 12 ++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index a0d2df9..378ebed 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -18,8 +18,8 @@ module cpu #( output reg we_o, input wire timer_interrupt, input wire external_interrupt, - output reg timer_interrupt_enable, - output reg external_interrupt_enable + output wire timer_interrupt_enable, + output wire external_interrupt_enable ); `include "params.vh" @@ -147,6 +147,10 @@ always @(posedge(clk_i)) begin if(rst_i) begin state <= STATE_RESET; instruction <= 32'hxxxx_xxxx; + mcause <= 0; + mepc <= 0; + mie <= 0; + mstatus <= 0; end else begin case(state) STATE_FETCH: diff --git a/sim/cpu.v b/sim/cpu.v index db7cbe9..d834b1a 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -24,6 +24,9 @@ wire ack_i; wire err_i = 0; wire rty_i = 0; +wire timer_interrupt; +wire timer_interrupt_enable; + cpu #(.INITIAL_PC('h1000_0000)) dut ( .clk_i(clk), .dat_i(dat_i), @@ -36,7 +39,10 @@ cpu #(.INITIAL_PC('h1000_0000)) dut ( .cyc_o(cyc_o), .adr_o(adr_o), .sel_o(sel_o), - .we_o(we_o) + .we_o(we_o), + .timer_interrupt(timer_interrupt), + .timer_interrupt_enable(timer_interrupt_enable), + .external_interrupt(0) ); wire flash_ack_o; @@ -84,7 +90,9 @@ mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( .we_i(we_o), .ack_o(mtimer_ack_o), .err_o(err_i), - .rty_o(rty_i) + .rty_o(rty_i), + .interrupt_enable(timer_interrupt_enable), + .interrupt(timer_interrupt) ); wire gpio_ack_o; From 101ebe98005a976b4d91835985ac0a0a36095375 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 5 Sep 2024 22:49:42 +0100 Subject: [PATCH 26/88] configure trap handler address --- freertos/app/crush.ld | 2 ++ rtl/cpu/cpu.v | 1 + sim/cpu.v | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/freertos/app/crush.ld b/freertos/app/crush.ld index 2f3e841..a2cdf79 100644 --- a/freertos/app/crush.ld +++ b/freertos/app/crush.ld @@ -12,6 +12,8 @@ SECTIONS .flash : { . = ALIGN(4); KEEP(*(.start)) + . = 0x100; + KEEP(*(.text.freertos_risc_v_trap_handler)) *(.text .text.*) *(.rodata .rodata* .srodata .srodata.*) . = ALIGN(4); diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index 378ebed..bf17ea2 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -48,6 +48,7 @@ reg [31:0] mcause; reg [31:0] mepc; reg [31:0] mie; reg [31:0] mstatus; +wire [31:0] mtvec = TRAP_PC; wire mstatus_mie = mstatus[3]; diff --git a/sim/cpu.v b/sim/cpu.v index d834b1a..e2101d0 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -27,7 +27,7 @@ wire rty_i = 0; wire timer_interrupt; wire timer_interrupt_enable; -cpu #(.INITIAL_PC('h1000_0000)) dut ( +cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), From 8079c3c6cd0835f04bc9ff1b1f156ed4c8a77ff3 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 6 Sep 2024 21:53:50 +0100 Subject: [PATCH 27/88] WIP --- doc/Implementation progress.ods | Bin 12984 -> 19634 bytes rtl/cpu/mtimer.v | 1 + 2 files changed, 1 insertion(+) diff --git a/doc/Implementation progress.ods b/doc/Implementation progress.ods index e9f35fef1253291b1d191b4b0ffdd13ff923ca42..529645cee35ff8859ef0a54c63a81bd6f9fc7dd3 100644 GIT binary patch delta 17618 zcmZ_#byQnV)HV#`8l+eWP$=$cAb7Fj5Gd}!U5gfq1*f4 z1`HwG|7}YBfXH5&FA$QIB(M>*e6+?u~uY;V)%ztguE%U`5WV~&yoFtVE zQxo?s*|pjEnpkQOCJWqnPREaW-p}0Nr5;xH#z~#jOpFm$cK^Ue3dXv&I3={`4U|c# z$nr8pa2-;VwKXb>RT<&=Did2?j9WBo?YoJy@w~Cjt)a8y&>e}y&PNORP`TJzCy36! zGN`wgDc4?A3&*J_7Y|Lg1Ha@@3C!Riod0S-wCz$rTQJnhn-gvt?W!wlC6qW4JH1`S zGcgpLN0?Zc%dd&G9rRj^;&vrp<>ULLc;Xn_I(Z#YS1%Zb7gq*baw zE{IO~*PBCL%VI0`_AtFjcIs!(|1kySWoQs+5xcQzM(!QQv}8@G=m~wh_u76x6+UhP z33-OW7lXGB1HOjGY)0SL&7)pjd5h7f%)5eGj4HPbFoUb zO5c7eo4KH9>A%T@Y2OVzc$kn*tFn>aoF4{+x`*aw#Z(5~3*HScz3{Ya=8qMc z6>5s!-)Yx-yL_+T6R&?Y_kOiS)s>Y`Wg~w{VSLhAZ9yK6%Op2C-?*RD&l`46yu*J> zN^bDpERqGe%Oilxw})ZtXofK8_&7J`LXf!ZvtCXMaO7spV+T z`&sOoYW{^Q+!3VI+r3zL{_!wV`uO8k#mA<9riAHVtw7Y>+Bc+Jg=Y(Yw>;2am65k5 zEB|FI`P4m`CI{hr^ zH0rWZ&sCOvi5@wmQEJMu_|(WV7?hMwogRnAr=XolWNFZRFu+bB@kZt>W`np<)qkp{ z9G4Ww2|ma8<}Nd3)t&)DkKvb)ykj42K%T_kzyA#FI^B$f&C`wdQgeia-Zr=GW0IFZ;h(sJ=V)pE4?@4Ezu2+g zXH-U*L)whve_HZQ;|E{~CMdgU@qd={TeF5&Fzq!R&T?USlTD19zSq6M(~lge1N3U^ zN6OZnuzb(yovr)Ja_akG2{Lt4_voH>>Nl%M)EhCIchYlX2s{5-#J{_dVVe|ejDe*c zJE0NF#)ABG-6309%%fLZBIVCp=uq@$WURWhKB$MfdjA2k)+(jV)%3gLmd8KEQ{M{y z)Q^#JsWH2z>USuwYnX6Bdd*P_xrMAFa2N6uVm>=57^3^}jv~M1yNDT{Xv*iA_=(VD zD|B8J2U||}>Nh+@%-yl9oHnV4RCDmVdH2AOU1={ieESsq`?=H>Ajtm08{}$(k;Ej? zyNzbMP>()Q6H@sH9`G{uQ^*5w#Ss4U7ZcTk&oGDoW5=tvws!6^MN-TOo{Dd+&E9`{ z;L}oHH(d*wIqrFPRvpq@ZXt4U;K1yzQl&@Flnc>Schi|3n-e=~3EO=xQZ@IZ2dp@W z`$7=zsyOuE*;G7S`-r(Up#ImC<;LFecZ=sRRc{v^-R}eSKNU~X?@tc%sov$o7xNQ7 zrN5^4EVm$U`dwF%e1V-fJp1R=sJrz(vI?3KErtJYY*l#s;`++u

_${08VsiW_<& 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 P@xjRo7;wTYza{?*|BWY? diff --git a/rtl/cpu/mtimer.v b/rtl/cpu/mtimer.v index 76a06bf..2b583df 100644 --- a/rtl/cpu/mtimer.v +++ b/rtl/cpu/mtimer.v @@ -53,6 +53,7 @@ module mtimer #( if(rst_i) begin for(int i = 0; i < 4; i++) mem[i] <= 0; + interrupt <= 0; end else begin {mem[1], mem[0]} <= mtime + 1; From 67c8cb651095f5ce90e10aff5ef1b8f43b6cc9ed Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 23 Sep 2024 10:35:41 +0100 Subject: [PATCH 28/88] Set up test for CSR instructions --- .github/workflows/main.yml | 1 + crush.core | 13 ++ doc/Implementation progress.ods | Bin 19634 -> 19641 bytes rtl/cpu/cpu.v | 74 +++++++++--- rtl/cpu/mtimer.v | 3 +- rtl/cpu/params.vh | 5 + sim/cpu.v | 9 +- sim/csr_tb.v | 208 ++++++++++++++++++++++++++++++++ 8 files changed, 286 insertions(+), 27 deletions(-) create mode 100644 sim/csr_tb.v diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e452853..080a69a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,7 @@ jobs: - sim_inst_immediate_decode - sim_memory - sim_alu + - sim_csr - sim_load_store - sim_top - sim_mtimer diff --git a/crush.core b/crush.core index d0cc014..685a2ab 100644 --- a/crush.core +++ b/crush.core @@ -67,6 +67,11 @@ filesets: - sim/sim_memory.v file_type: verilogSource + sim_csr: + files: + - sim/csr_tb.v + file_type: systemVerilogSource + sim_mtimer: files: - sim/mtimer_tb.v @@ -147,6 +152,14 @@ targets: toplevel: alu_tb default_tool: icarus + sim_csr: + <<: *default + filesets_append: + - sim_common + - sim_csr + toplevel: csr_tb + default_tool: icarus + sim_load_store: <<: *default filesets_append: diff --git a/doc/Implementation progress.ods b/doc/Implementation progress.ods index 529645cee35ff8859ef0a54c63a81bd6f9fc7dd3..54f73481d1084bc8555c1bce6c073b767e939b7e 100644 GIT binary patch delta 7224 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 delta 7174 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 NQDS_?FZcVTe*xG+RZsu` diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index bf17ea2..758771b 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -17,9 +17,7 @@ module cpu #( output reg[3:0] sel_o, output reg we_o, input wire timer_interrupt, - input wire external_interrupt, - output wire timer_interrupt_enable, - output wire external_interrupt_enable + input wire external_interrupt ); `include "params.vh" @@ -44,6 +42,9 @@ reg[31:0] pc_value; wire[31:0] pc; wire[31:0] pc_inc; +reg trap_taken; +reg [31:0] mcause_; + reg [31:0] mcause; reg [31:0] mepc; reg [31:0] mie; @@ -55,8 +56,8 @@ wire mstatus_mie = mstatus[3]; wire mie_mtie = mie[7]; wire mie_meie = mie[11]; -assign timer_interrupt_enable = mstatus_mie && mie_mtie; -assign external_interrupt_enable = mstatus_mie && mie_meie; +wire timer_interrupt_enable = mstatus_mie && mie_mtie; +wire external_interrupt_enable = mstatus_mie && mie_meie; program_counter #(.INITIAL_PC(INITIAL_PC)) program_counter( .reset(rst_i), @@ -90,6 +91,7 @@ registers registers( assign r_address1 = instruction[19:15]; assign r_address2 = instruction[24:20]; assign w_address = instruction[11:7]; +wire [11:0] csr_address = instruction[31:20]; reg[31:0] alu_op_a; reg[31:0] alu_op_b; @@ -159,7 +161,21 @@ always @(posedge(clk_i)) begin state <= STATE_REG_READ; instruction <= dat_i; end - STATE_REG_READ: state <= STATE_EXECUTE; + STATE_REG_READ: begin + state <= STATE_EXECUTE; + + if(opcode == OPCODE_SYSTEM) begin + if(funct3 == FUNCT3_CSRRW) begin + case(csr_address) + CSR_MSTATUS: mstatus <= r_out1; + CSR_MIE: mie <= r_out1; + CSR_MEPC: mepc <= r_out1; + CSR_MCAUSE: mcause <= r_out1; + default: ; + endcase + end + end + end STATE_EXECUTE: begin state <= STATE_MEMORY; state_change <= 0; @@ -169,7 +185,13 @@ always @(posedge(clk_i)) begin state <= STATE_REG_WRITE; read_data <= dat_i; end else state_change <= 0; - STATE_REG_WRITE: state <= STATE_FETCH; + STATE_REG_WRITE: begin + state <= STATE_FETCH; + if(trap_taken) begin + mcause <= mcause_; + mepc <= pc; + end + end default: state <= STATE_FETCH; endcase end @@ -186,6 +208,16 @@ always @(*) begin OPCODE_JAL, OPCODE_JALR, OPCODE_LOAD: reg_w_en = 1; + OPCODE_SYSTEM: + case(funct3) + FUNCT3_CSRRW, + FUNCT3_CSRRWI, + FUNCT3_CSRRC, + FUNCT3_CSRRCI, + FUNCT3_CSRRS, + FUNCT3_CSRRSI: reg_w_en = 1; + default: reg_w_en = 0; + endcase default: reg_w_en = 0; endcase end @@ -213,6 +245,9 @@ always @(*) begin pc_load = 0; pc_value = 32'hxxxx_xxxx; + trap_taken = 0; + mcause_ = 32'hxxxx_xxxx; + stb_o = 0; cyc_o = 0; sel_o = 4'hx; @@ -268,27 +303,28 @@ always @(*) begin endcase end - - if(timer_interrupt || external_interrupt) begin + if((timer_interrupt && timer_interrupt_enable) + || (external_interrupt && external_interrupt_enable)) begin // Prevent memory writes if interrupted. This is the only side effect // of the instruction, so this effectively interrupts the instruction, // and it can be restarted after handling the interrupt. - stb_o = 0; - cyc_o = 0; - sel_o = 4'hx; - dat_o = 32'hxxxx_xxxx; - adr_o = 32'hxxxx_xxxx; - we_o = 1'hx; + stb_o = 0; + cyc_o = 0; + sel_o = 4'hx; + dat_o = 32'hxxxx_xxxx; + adr_o = 32'hxxxx_xxxx; + we_o = 1'hx; - mepc = pc_value; - pc_value = TRAP_PC; + trap_taken = 1; + pc_value = TRAP_PC; + pc_load = 1; if(timer_interrupt) begin - mcause = 7; + mcause_ = {1'b1, 31'd7}; end if(external_interrupt) begin - mcause = 11; + mcause_ = {1'b1, 31'd11}; end end end diff --git a/rtl/cpu/mtimer.v b/rtl/cpu/mtimer.v index 2b583df..0fe456d 100644 --- a/rtl/cpu/mtimer.v +++ b/rtl/cpu/mtimer.v @@ -17,7 +17,6 @@ module mtimer #( output reg err_o, output reg rty_o, // interrupt - input wire interrupt_enable, output reg interrupt ); // The number of 32-bit registers that can be addressed inside this @@ -70,7 +69,7 @@ module mtimer #( end end - if(interrupt_enable && mtime == mtimecmp) interrupt <= 1; + interrupt <= 1; if(mtimecmp > mtime) interrupt <= 0; end end diff --git a/rtl/cpu/params.vh b/rtl/cpu/params.vh index 8e9d696..cd244a3 100644 --- a/rtl/cpu/params.vh +++ b/rtl/cpu/params.vh @@ -56,4 +56,9 @@ localparam FUNCT3_CSRRWI = 3'b101; localparam FUNCT3_CSRRSI = 3'b110; localparam FUNCT3_CSRRCI = 3'b111; localparam FUNCT3_PRIV = 3'b000; + +localparam CSR_MSTATUS = 12'h300; +localparam CSR_MIE = 12'h304; +localparam CSR_MEPC = 12'h341; +localparam CSR_MCAUSE = 12'h342; // verilator lint_on UNUSEDPARAM diff --git a/sim/cpu.v b/sim/cpu.v index e2101d0..b140f5b 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -25,7 +25,6 @@ wire err_i = 0; wire rty_i = 0; wire timer_interrupt; -wire timer_interrupt_enable; cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( .clk_i(clk), @@ -41,8 +40,7 @@ cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( .sel_o(sel_o), .we_o(we_o), .timer_interrupt(timer_interrupt), - .timer_interrupt_enable(timer_interrupt_enable), - .external_interrupt(0) + .external_interrupt(1'b0) ); wire flash_ack_o; @@ -91,7 +89,6 @@ mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( .ack_o(mtimer_ack_o), .err_o(err_i), .rty_o(rty_i), - .interrupt_enable(timer_interrupt_enable), .interrupt(timer_interrupt) ); @@ -134,9 +131,9 @@ initial begin $dumpvars(0); #250 reset = 0; - #50 + #50; - #300_000_000 + #300_000_000; $error("Stop was not called within 300 ms, stopping now"); $fatal; diff --git a/sim/csr_tb.v b/sim/csr_tb.v new file mode 100644 index 0000000..293dc0b --- /dev/null +++ b/sim/csr_tb.v @@ -0,0 +1,208 @@ +/* Test bench for CSR instructions CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI */ + +/* Most of the implemented CSRs are not arbitrary read/write registers. Instead + * they are WARL etc. + * + * The most straight forward register to use for testing is the mepc, where + * every bit other than the last two are always readable and writable. + * It will also never be written by the system as long as software does not + * enable interrupts. + */ +`default_nettype none + +`include "fatal_assert.vh" + +module csr_tb; + +`include "params.vh" + +reg clk = 1; +reg reset = 1; +wire stb_o; +wire cyc_o; +wire[31:0] adr_o; +wire[3:0] sel_o; +wire[31:0] dat_i; +wire[31:0] dat_o; +wire we_o; +wire ack_i; +wire err_i = 0; +wire rty_i = 0; + +string test_case_name = ""; + +reg flash_ack_o = 0; +reg[31:0] flash_dat_o = 32'hzzzz_zzzz; + +cpu #(.INITIAL_PC('h1000_0000)) cpu ( + .clk_i(clk), + .dat_i(dat_i), + .dat_o(dat_o), + .rst_i(reset), + .ack_i(ack_i), + .err_i(err_i), + .rty_i(rty_i), + .stb_o(stb_o), + .cyc_o(cyc_o), + .adr_o(adr_o), + .sel_o(sel_o), + .we_o(we_o) +); + +wire memory_ack_o; +sim_memory #(.BASE_ADDRESS('h2000_0000), .SIZE('h4000)) memory ( + .clk_i(clk), + .rst_i(reset), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(memory_ack_o), + .err_o(err_i), + .rty_o(rty_i) +); + +assign ack_i = flash_ack_o | memory_ack_o; +assign dat_i = flash_dat_o; +integer count = 0; + +always begin + #0.5 + clk <= !clk; + #0.5 + clk <= !clk; + count <= count + 1; +end + +task static test_case(input string a_test_case_name); + @(posedge clk) + reset = 1; + test_case_name = a_test_case_name; + + @(posedge clk) reset = 0; +endtask + + +task static LW(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset}, {rs1}, {FUNCT3_LW}, {rd}, {OPCODE_LOAD}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static LB(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset}, {rs1}, {FUNCT3_LB}, {rd}, {OPCODE_LOAD}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static LBU(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset}, {rs1}, {FUNCT3_LBU}, {rd}, {OPCODE_LOAD}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static LH(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset}, {rs1}, {FUNCT3_LH}, {rd}, {OPCODE_LOAD}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static LHU(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset}, {rs1}, {FUNCT3_LHU}, {rd}, {OPCODE_LOAD}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static SW(input reg[4:0] rs2, input reg[4:0] rs1, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset[11:5]}, {rs2}, {rs1}, {FUNCT3_SW}, {offset[4:0]}, {OPCODE_STORE}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static SH(input reg[4:0] rs2, input reg[4:0] rs1, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset[11:5]}, {rs2}, {rs1}, {FUNCT3_SH}, {offset[4:0]}, {OPCODE_STORE}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static SB(input reg[4:0] rs2, input reg[4:0] rs1, input reg[11:0] offset); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{offset[11:5]}, {rs2}, {rs1}, {FUNCT3_SB}, {offset[4:0]}, {OPCODE_STORE}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +initial begin + $dumpfile("csr_tb.vcd"); + $dumpvars(0); + + test_case("load word, no offset"); + + cpu.registers.memory[1] = 32'h2000_0000; + memory.mem[0] = 32'h0000_0001; + + LW(1, 1, 12'h000); + @(ack_i); + @(posedge clk); + @(posedge clk); + #1 + `fatal_assert (cpu.registers.x1 == 32'h0000_0001); + + test_case("CSSRW"); + + `fatal_assert(1 == 2); + + $stop; +end + +endmodule From ce8848b12229dbe6d21e91cbb3972b42a010a721 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 23 Sep 2024 14:41:45 +0100 Subject: [PATCH 29/88] Implement csrrw --- rtl/cpu/alu.v | 12 +++++- rtl/cpu/cpu.v | 29 +++++++++++-- rtl/cpu/inst_immediate_decode.v | 4 +- sim/csr_tb.v | 72 ++++++++++++--------------------- tools/csr_tb.gtkw | 62 ++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 53 deletions(-) create mode 100644 tools/csr_tb.gtkw diff --git a/rtl/cpu/alu.v b/rtl/cpu/alu.v index cde9234..9a72b8e 100644 --- a/rtl/cpu/alu.v +++ b/rtl/cpu/alu.v @@ -21,6 +21,7 @@ module alu ( wire [31:0] B_immediate; wire [31:0] U_immediate; wire [31:0] J_immediate; + wire [31:0] CSR_immediate; inst_immediate_decode immediate_decode ( .inst(instruction), @@ -28,7 +29,8 @@ module alu ( .S_immediate(S_immediate), .B_immediate(B_immediate), .U_immediate(U_immediate), - .J_immediate(J_immediate) + .J_immediate(J_immediate), + .CSR_immediate(CSR_immediate) ); wire [6:0] opcode = instruction[6:0]; @@ -78,6 +80,14 @@ module alu ( OPCODE_STORE: out = op_a + S_immediate; OPCODE_JAL: out = pc + J_immediate; OPCODE_JALR: out = (op_a + I_immediate) & ~1; + OPCODE_SYSTEM: case(funct3) + FUNCT3_CSRRW: out = op_a; + FUNCT3_CSRRWI: out = CSR_immediate; + FUNCT3_CSRRC: out = op_a & ~op_b; + FUNCT3_CSRRCI: out = op_a & ~CSR_immediate; + FUNCT3_CSRRS: out = op_a | op_b; + FUNCT3_CSRRSI: out = op_a | CSR_immediate; + endcase default: ; endcase end diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index 758771b..ca78801 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -51,6 +51,8 @@ reg [31:0] mie; reg [31:0] mstatus; wire [31:0] mtvec = TRAP_PC; +reg [31:0] csr_read_value; + wire mstatus_mie = mstatus[3]; wire mie_mtie = mie[7]; @@ -167,14 +169,15 @@ always @(posedge(clk_i)) begin if(opcode == OPCODE_SYSTEM) begin if(funct3 == FUNCT3_CSRRW) begin case(csr_address) - CSR_MSTATUS: mstatus <= r_out1; - CSR_MIE: mie <= r_out1; - CSR_MEPC: mepc <= r_out1; - CSR_MCAUSE: mcause <= r_out1; + CSR_MSTATUS: csr_read_value <= mstatus; + CSR_MIE: csr_read_value <= mie; + CSR_MEPC: csr_read_value <= mepc; + CSR_MCAUSE: csr_read_value <= mcause; default: ; endcase end end + end STATE_EXECUTE: begin state <= STATE_MEMORY; @@ -187,6 +190,19 @@ always @(posedge(clk_i)) begin end else state_change <= 0; STATE_REG_WRITE: begin state <= STATE_FETCH; + + if(opcode == OPCODE_SYSTEM) begin + if(funct3 == FUNCT3_CSRRW) begin + case(csr_address) + CSR_MSTATUS: mstatus <= r_out1; + CSR_MIE: mie <= r_out1; + CSR_MEPC: mepc <= r_out1; + CSR_MCAUSE: mcause <= r_out1; + default: ; + endcase + end + end + if(trap_taken) begin mcause <= mcause_; mepc <= pc; @@ -274,6 +290,10 @@ always @(*) begin STATE_EXECUTE: begin alu_op_a = r_out1; alu_op_b = r_out2; + + if(opcode == OPCODE_SYSTEM) begin + alu_op_a = csr_read_value; + end end STATE_MEMORY: begin if(mem_r_en) begin @@ -346,6 +366,7 @@ always @(*) begin OPCODE_JALR: begin w_data = pc_inc; end + OPCODE_SYSTEM: w_data = csr_read_value; default: w_data = alu_out_r; endcase diff --git a/rtl/cpu/inst_immediate_decode.v b/rtl/cpu/inst_immediate_decode.v index 94eba6d..b29d9d4 100644 --- a/rtl/cpu/inst_immediate_decode.v +++ b/rtl/cpu/inst_immediate_decode.v @@ -6,7 +6,8 @@ module inst_immediate_decode( output reg[31:0] S_immediate, output reg[31:0] B_immediate, output reg[31:0] U_immediate, - output reg[31:0] J_immediate + output reg[31:0] J_immediate, + output reg[31:0] CSR_immediate ); @@ -16,6 +17,7 @@ always @* begin B_immediate = { {20{inst[31]}}, inst[7], inst[30:25], inst[11:8], 1'b0}; U_immediate = { inst[31], inst[30:20], inst[19:12], 12'b0}; J_immediate = { {12{inst[31]}}, inst[19:12], inst[20], inst[30:25], inst[24:21], 1'b0}; + CSR_immediate = { 27'b0, inst[19:15]}; end endmodule diff --git a/sim/csr_tb.v b/sim/csr_tb.v index 293dc0b..f7b7c42 100644 --- a/sim/csr_tb.v +++ b/sim/csr_tb.v @@ -85,97 +85,72 @@ task static test_case(input string a_test_case_name); @(posedge clk) reset = 0; endtask - -task static LW(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); +task static CSRRW(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{offset}, {rs1}, {FUNCT3_LW}, {rd}, {OPCODE_LOAD}}; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRW}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; #0; endtask -task static LB(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); +task static CSRRS(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{offset}, {rs1}, {FUNCT3_LB}, {rd}, {OPCODE_LOAD}}; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRS}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; #0; endtask -task static LBU(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); +task static CSRRC(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{offset}, {rs1}, {FUNCT3_LBU}, {rd}, {OPCODE_LOAD}}; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRC}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; #0; endtask -task static LH(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); +task static CSRRWI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{offset}, {rs1}, {FUNCT3_LH}, {rd}, {OPCODE_LOAD}}; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRWI}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; #0; endtask -task static LHU(input reg[4:0] rs1, input reg[4:0] rd, input reg[11:0] offset); +task static CSRRSI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{offset}, {rs1}, {FUNCT3_LHU}, {rd}, {OPCODE_LOAD}}; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRSI}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; #0; endtask -task static SW(input reg[4:0] rs2, input reg[4:0] rs1, input reg[11:0] offset); +task static CSRRCI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{offset[11:5]}, {rs2}, {rs1}, {FUNCT3_SW}, {offset[4:0]}, {OPCODE_STORE}}; - @(posedge clk); - flash_ack_o = 0; - flash_dat_o = 32'hzzzz_zzzz; - #0; -endtask - -task static SH(input reg[4:0] rs2, input reg[4:0] rs1, input reg[11:0] offset); - // wait for wishbone instruction read - @(stb_o & cyc_o); - @(posedge clk); - flash_ack_o = 1; - flash_dat_o = {{offset[11:5]}, {rs2}, {rs1}, {FUNCT3_SH}, {offset[4:0]}, {OPCODE_STORE}}; - @(posedge clk); - flash_ack_o = 0; - flash_dat_o = 32'hzzzz_zzzz; - #0; -endtask - -task static SB(input reg[4:0] rs2, input reg[4:0] rs1, input reg[11:0] offset); - // wait for wishbone instruction read - @(stb_o & cyc_o); - @(posedge clk); - flash_ack_o = 1; - flash_dat_o = {{offset[11:5]}, {rs2}, {rs1}, {FUNCT3_SB}, {offset[4:0]}, {OPCODE_STORE}}; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRCI}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; @@ -186,21 +161,24 @@ initial begin $dumpfile("csr_tb.vcd"); $dumpvars(0); - test_case("load word, no offset"); + test_case("CSRRW"); - cpu.registers.memory[1] = 32'h2000_0000; - memory.mem[0] = 32'h0000_0001; + cpu.registers.memory[1] = 32'h0000_00A0; + cpu.registers.memory[2] = 32'h0000_00B0; + + CSRRW(1, CSR_MEPC, 2); - LW(1, 1, 12'h000); - @(ack_i); - @(posedge clk); - @(posedge clk); #1 - `fatal_assert (cpu.registers.x1 == 32'h0000_0001); + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0000); + `fatal_assert (cpu.mepc == 32'h0000_00B0); - test_case("CSSRW"); + CSRRW(1, CSR_MEPC, 2); - `fatal_assert(1 == 2); + #1 + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_00B0); + `fatal_assert (cpu.mepc == 32'h0000_00B0); $stop; end diff --git a/tools/csr_tb.gtkw b/tools/csr_tb.gtkw new file mode 100644 index 0000000..60be202 --- /dev/null +++ b/tools/csr_tb.gtkw @@ -0,0 +1,62 @@ +[*] +[*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI +[*] Mon Sep 23 12:50:59 2024 +[*] +[dumpfile] "/home/barabas/data3/projects/hardware/risc-v/build/crush_0.0.1/sim_csr-icarus/csr_tb.vcd" +[dumpfile_mtime] "Mon Sep 23 12:43:01 2024" +[dumpfile_size] 3172 +[savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/csr_tb.gtkw" +[timestart] 0 +[size] 2560 1345 +[pos] -1 -1 +*-2.196938 11 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] csr_tb. +[treeopen] csr_tb.cpu. +[sst_width] 286 +[signals_width] 277 +[sst_expanded] 1 +[sst_vpaned_height] 416 +@28 +csr_tb.reset +csr_tb.clk +@200 +- +@2029 +^1 /home/barabas/data3/projects/hardware/risc-v/tools/cpu_state_filter.txt +csr_tb.cpu.state[2:0] +@200 +- +@28 +csr_tb.cyc_o +csr_tb.stb_o +@22 +csr_tb.adr_o[31:0] +csr_tb.dat_o[31:0] +csr_tb.dat_i[31:0] +@28 +csr_tb.ack_i +csr_tb.err_i +csr_tb.rty_i +@200 +- +@28 +csr_tb.flash_ack_o +@22 +csr_tb.flash_dat_o[31:0] +@28 +csr_tb.memory_ack_o +@22 +csr_tb.sel_o[3:0] +@28 +csr_tb.we_o +@200 +- +@22 +csr_tb.cpu.mepc[31:0] +@200 +- +@22 +csr_tb.cpu.registers.x1[31:0] +csr_tb.cpu.registers.x2[31:0] +[pattern_trace] 1 +[pattern_trace] 0 From 548fc32769386f3c1a341f9f92fa58f69aa9b581 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 23 Sep 2024 15:04:27 +0100 Subject: [PATCH 30/88] Implement csrrs --- rtl/cpu/cpu.v | 35 ++++++++++++++++------------------- sim/csr_tb.v | 27 +++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index ca78801..a8831b0 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -167,15 +167,13 @@ always @(posedge(clk_i)) begin state <= STATE_EXECUTE; if(opcode == OPCODE_SYSTEM) begin - if(funct3 == FUNCT3_CSRRW) begin - case(csr_address) - CSR_MSTATUS: csr_read_value <= mstatus; - CSR_MIE: csr_read_value <= mie; - CSR_MEPC: csr_read_value <= mepc; - CSR_MCAUSE: csr_read_value <= mcause; - default: ; - endcase - end + case(csr_address) + CSR_MSTATUS: csr_read_value <= mstatus; + CSR_MIE: csr_read_value <= mie; + CSR_MEPC: csr_read_value <= mepc; + CSR_MCAUSE: csr_read_value <= mcause; + default: ; + endcase end end @@ -192,15 +190,13 @@ always @(posedge(clk_i)) begin state <= STATE_FETCH; if(opcode == OPCODE_SYSTEM) begin - if(funct3 == FUNCT3_CSRRW) begin - case(csr_address) - CSR_MSTATUS: mstatus <= r_out1; - CSR_MIE: mie <= r_out1; - CSR_MEPC: mepc <= r_out1; - CSR_MCAUSE: mcause <= r_out1; - default: ; - endcase - end + case(csr_address) + CSR_MSTATUS: mstatus <= alu_out_r; + CSR_MIE: mie <= alu_out_r; + CSR_MEPC: mepc <= alu_out_r; + CSR_MCAUSE: mcause <= alu_out_r; + default: ; + endcase end if(trap_taken) begin @@ -291,8 +287,9 @@ always @(*) begin alu_op_a = r_out1; alu_op_b = r_out2; - if(opcode == OPCODE_SYSTEM) begin + if((opcode == OPCODE_SYSTEM) && (funct3 != FUNCT3_CSRRW)) begin alu_op_a = csr_read_value; + alu_op_b = r_out1; end end STATE_MEMORY: begin diff --git a/sim/csr_tb.v b/sim/csr_tb.v index f7b7c42..811650e 100644 --- a/sim/csr_tb.v +++ b/sim/csr_tb.v @@ -77,9 +77,18 @@ always begin count <= count + 1; end +task static reset_registers(); + integer i; + for (i = 0; i < 32; i++) begin + cpu.registers.memory[i] = 32'hxxxx_xxxx; + end +endtask + task static test_case(input string a_test_case_name); @(posedge clk) reset = 1; + reset_registers; + test_case_name = a_test_case_name; @(posedge clk) reset = 0; @@ -168,17 +177,31 @@ initial begin CSRRW(1, CSR_MEPC, 2); - #1 + #1; @(cpu.state == cpu.STATE_FETCH); `fatal_assert (cpu.registers.x1 == 32'h0000_0000); `fatal_assert (cpu.mepc == 32'h0000_00B0); CSRRW(1, CSR_MEPC, 2); - #1 + #1; @(cpu.state == cpu.STATE_FETCH); `fatal_assert (cpu.registers.x1 == 32'h0000_00B0); `fatal_assert (cpu.mepc == 32'h0000_00B0); + #1; + + test_case("CSRRS"); + + cpu.mepc = 32'h1010_0000; + cpu.registers.memory[2] = 32'h1100_0000; + + CSRRS(1, CSR_MEPC, 2); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h1010_0000); + `fatal_assert (cpu.mepc == 32'h1110_0000); + #1; $stop; end From a5e962533138c41b71a2776da78e3e781c7ce7fb Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 23 Sep 2024 15:07:06 +0100 Subject: [PATCH 31/88] Implement csrrc --- sim/csr_tb.v | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sim/csr_tb.v b/sim/csr_tb.v index 811650e..a3ed297 100644 --- a/sim/csr_tb.v +++ b/sim/csr_tb.v @@ -203,6 +203,19 @@ initial begin `fatal_assert (cpu.mepc == 32'h1110_0000); #1; + test_case("CSRRC"); + + cpu.mepc = 32'h1010_0000; + cpu.registers.memory[2] = 32'h1100_0000; + + CSRRC(1, CSR_MEPC, 2); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h1010_0000); + `fatal_assert (cpu.mepc == 32'h0010_0000); + #1; + $stop; end From 77e451216b6aa5ba21a5fbe49d3617c7cb00d539 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 23 Sep 2024 15:15:43 +0100 Subject: [PATCH 32/88] Implement immediate csrs --- doc/Implementation progress.ods | Bin 19641 -> 13635 bytes sim/csr_tb.v | 48 ++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/doc/Implementation progress.ods b/doc/Implementation progress.ods index 54f73481d1084bc8555c1bce6c073b767e939b7e..72e7ab3418c8b2a907d2bfc75470417cc5e9dc0c 100644 GIT binary patch delta 11750 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 YKTV{WPP$Fb*B76xYbwBI=K)d%0Pm$AZvX%Q diff --git a/sim/csr_tb.v b/sim/csr_tb.v index a3ed297..7c55fa3 100644 --- a/sim/csr_tb.v +++ b/sim/csr_tb.v @@ -130,36 +130,36 @@ task static CSRRC(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); #0; endtask -task static CSRRWI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); +task static CSRRWI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] imm); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRWI}, {rd}, {OPCODE_SYSTEM}}; + flash_dat_o = {{csr}, {imm}, {FUNCT3_CSRRWI}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; #0; endtask -task static CSRRSI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); +task static CSRRSI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] imm); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRSI}, {rd}, {OPCODE_SYSTEM}}; + flash_dat_o = {{csr}, {imm}, {FUNCT3_CSRRSI}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; #0; endtask -task static CSRRCI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); +task static CSRRCI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] imm); // wait for wishbone instruction read @(stb_o & cyc_o); @(posedge clk); flash_ack_o = 1; - flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRCI}, {rd}, {OPCODE_SYSTEM}}; + flash_dat_o = {{csr}, {imm}, {FUNCT3_CSRRCI}, {rd}, {OPCODE_SYSTEM}}; @(posedge clk); flash_ack_o = 0; flash_dat_o = 32'hzzzz_zzzz; @@ -216,6 +216,42 @@ initial begin `fatal_assert (cpu.mepc == 32'h0010_0000); #1; + test_case("CSRRWI"); + + cpu.mepc = 32'h0000_0014; + + CSRRWI(1, CSR_MEPC, 5'h18); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0014); + `fatal_assert (cpu.mepc == 32'h0000_0018); + #1; + + test_case("CSRRSI"); + + cpu.mepc = 32'h0000_0014; + + CSRRSI(1, CSR_MEPC, 5'h18); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0014); + `fatal_assert (cpu.mepc == 32'h0000_001C); + #1; + + test_case("CSRRCI"); + + cpu.mepc = 32'h0000_0014; + + CSRRCI(1, CSR_MEPC, 5'h18); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0014); + `fatal_assert (cpu.mepc == 32'h0000_0004); + #1; + $stop; end From 0c51e99e047d6fcaaefd4c6ab0db9aa4b00b9087 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 23 Sep 2024 16:18:00 +0100 Subject: [PATCH 33/88] implement exception stack management --- rtl/cpu/cpu.v | 16 +++++++++++----- tools/csr_tb.gtkw | 31 ++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index a8831b0..b148d2e 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -182,10 +182,21 @@ always @(posedge(clk_i)) begin state_change <= 0; end STATE_MEMORY: + begin if(ack_i | (!mem_r_en & !mem_w_en)) begin state <= STATE_REG_WRITE; read_data <= dat_i; end else state_change <= 0; + + if(trap_taken) begin + mcause <= mcause_; + mepc <= pc; + state <= STATE_FETCH; + + mstatus[7] <= 1; + mstatus[3] <= 0; + end + end STATE_REG_WRITE: begin state <= STATE_FETCH; @@ -198,11 +209,6 @@ always @(posedge(clk_i)) begin default: ; endcase end - - if(trap_taken) begin - mcause <= mcause_; - mepc <= pc; - end end default: state <= STATE_FETCH; endcase diff --git a/tools/csr_tb.gtkw b/tools/csr_tb.gtkw index 60be202..2b975f9 100644 --- a/tools/csr_tb.gtkw +++ b/tools/csr_tb.gtkw @@ -1,27 +1,28 @@ [*] [*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI -[*] Mon Sep 23 12:50:59 2024 +[*] Mon Sep 23 14:34:37 2024 [*] [dumpfile] "/home/barabas/data3/projects/hardware/risc-v/build/crush_0.0.1/sim_csr-icarus/csr_tb.vcd" -[dumpfile_mtime] "Mon Sep 23 12:43:01 2024" -[dumpfile_size] 3172 +[dumpfile_mtime] "Mon Sep 23 14:15:20 2024" +[dumpfile_size] 4669 [savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/csr_tb.gtkw" -[timestart] 0 +[timestart] 22 [size] 2560 1345 [pos] -1 -1 -*-2.196938 11 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-2.196938 61 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] csr_tb. [treeopen] csr_tb.cpu. +[treeopen] csr_tb.cpu.registers. [sst_width] 286 [signals_width] 277 [sst_expanded] 1 -[sst_vpaned_height] 416 +[sst_vpaned_height] 415 @28 csr_tb.reset csr_tb.clk @200 - -@2029 +@2028 ^1 /home/barabas/data3/projects/hardware/risc-v/tools/cpu_state_filter.txt csr_tb.cpu.state[2:0] @200 @@ -58,5 +59,21 @@ csr_tb.cpu.mepc[31:0] @22 csr_tb.cpu.registers.x1[31:0] csr_tb.cpu.registers.x2[31:0] +@200 +- +@22 +csr_tb.cpu.registers.r_address1[4:0] +csr_tb.cpu.registers.r_out1[31:0] +csr_tb.cpu.registers.w_address[4:0] +csr_tb.cpu.registers.w_data[31:0] +@200 +- +@22 +csr_tb.cpu.alu.op_a[31:0] +csr_tb.cpu.alu.op_b[31:0] +csr_tb.cpu.alu.opcode[6:0] +csr_tb.cpu.alu.out[31:0] +csr_tb.cpu.alu_out[31:0] +csr_tb.cpu.alu_out_r[31:0] [pattern_trace] 1 [pattern_trace] 0 From bf30291d6a55b2c416919bcbaef712af2efa04b0 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Mon, 23 Sep 2024 16:43:23 +0100 Subject: [PATCH 34/88] Implement mret --- rtl/cpu/cpu.v | 24 ++++++++++++++++++++++-- rtl/cpu/params.vh | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index b148d2e..2cdd78f 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -193,15 +193,26 @@ always @(posedge(clk_i)) begin mepc <= pc; state <= STATE_FETCH; - mstatus[7] <= 1; + // MIE mstatus[3] <= 0; + // MPIE + mstatus[7] <= 1; end end STATE_REG_WRITE: begin state <= STATE_FETCH; if(opcode == OPCODE_SYSTEM) begin - case(csr_address) + if(w_address == 0 && + funct3 == FUNCT3_PRIV && + r_address1 == 0 && + instruction[31:20] == FUNCT12_MRET) begin + // MIE + mstatus[3] <= 1; + // MPIE + mstatus[7] <= 1; + end + else case(csr_address) CSR_MSTATUS: mstatus <= alu_out_r; CSR_MIE: mie <= alu_out_r; CSR_MEPC: mepc <= alu_out_r; @@ -402,6 +413,15 @@ always @(*) begin pc_value = 32'hxxxx_xxxx; end endcase + + if(opcode == OPCODE_SYSTEM && + w_address == 0 && + funct3 == FUNCT3_PRIV && + r_address1 == 0 && + instruction[31:20] == FUNCT12_MRET) begin + pc_load = 1; + pc_value = mepc; + end end default: ; endcase diff --git a/rtl/cpu/params.vh b/rtl/cpu/params.vh index cd244a3..103e926 100644 --- a/rtl/cpu/params.vh +++ b/rtl/cpu/params.vh @@ -61,4 +61,6 @@ localparam CSR_MSTATUS = 12'h300; localparam CSR_MIE = 12'h304; localparam CSR_MEPC = 12'h341; localparam CSR_MCAUSE = 12'h342; + +localparam FUNCT12_MRET = 12'b001100000010; // verilator lint_on UNUSEDPARAM From bad5d4a738a5ee5ee4aad447265174af2c66126c Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 25 Sep 2024 12:43:59 +0100 Subject: [PATCH 35/88] WIP --- doc/Implementation progress.ods | Bin 13635 -> 13878 bytes dump-firmware.sh | 1 + freertos/app/src/main.c | 2 -- tools/cpu2.gtkw | 61 ++++++++++++++++++++++++++------ 4 files changed, 51 insertions(+), 13 deletions(-) create mode 100755 dump-firmware.sh diff --git a/doc/Implementation progress.ods b/doc/Implementation progress.ods index 72e7ab3418c8b2a907d2bfc75470417cc5e9dc0c..851e911c86e5fb8e62ad816ea2d07b7886e987ac 100644 GIT binary patch delta 8849 zcmcI~cQjmW*ZwHcG6c~H(SnFJx*%GRj3K({y)zgk5eyL|Y8btX8ol>kMkmp`Xd`;> z?c;sk=X;;``PT3KN=O|~SeU2NKkIZoo{{B`seE7En7P>nY`#`IZ%>kH31?Se!}ng;mp z%$QhvyX3WF-SnhYRVtKzde5SBt8N;+lzMf&9KgtzBtk|r(S;}WTeVF}+-#mhV2Z^T zAl;e_2!Tg_nxK0uK?BclVUKk7$+&~CSXT{ z$1Mrjr?fS-q!`%%Jt}=ln&sO?J3U41o6yi0c9mTUDpDKG}`(A5;sXv!AiRr*PH!BRt%KffK8d#q52wD9|#9B3aRTGln} z_#B7LIMdsNGCY|N^V?w5nO05$RnSj4_H}~1(m6xZ?LS_^0xy45!4Gq5T6X)y2TRWpZ{z1BdKN)<3 zD!Ni-$f1eS76KNyF4?f^rrzL~C45}IHxiE?RQrp%2n%}4~(ZFt{>kn`y zU+rKLqICc&`v<;ndLxzI3zb*jgAWOBjm23jA6u@gaeRbXSdy6^RhxX=>@*W@COB<= z0>fGB4*$&PMTRqLna+okA?gu9sI#6Z(r8z0h^`lrKcnSeL=3c0z!1=yY;AFZF3WS! zj8_6GyPa^q4E*LLBhl^hf~a-r?!9DI=iB6)3w)}N%bnL8{aD6ArUw5DFZ^KXUIgkf zu6$w`EMIoosQy%j28V9tp1ey^gG_b~n~8F(JpSXl(<98@-@ z-`q(4xlFV?YU)wwwl)cIt}DFMHomO-RKxy~iU*NN)~`UQ5!5qxUuI?ZvYu9OL$!mK z$a4}zTV~`8AM#*dzR(V+(yn!Rm$!VeJ-lP_`lNDeXc9`6luZu*{aaoBB;Y=zN~Ly( zZyxWAcGkK!YN()1hk1Tndk*6P$cUbDq z-&mV>Hlzo=Vm7@VHRN=e>HPuEd%IVND|3Zzj6Z#zE#~JOc0{yXv7A=IX=4zQC-9*y z2Qh(k-hfE6&7ZT#RluD$b~XB{u0u3A7UH2%9`iu{+1G1hXF6>2wdWe(DuO#~)Wafu z&5LaI9O5bLjjCQR^HML0wNE-F-S>2XDIYX|(75)$IS>jmtmWd`r2AK=b;qd+I9+ieodglVTGaTdRomhximR5@=r19LE4=v!w42 z*qV9e@qw3=&+2Cp4@e%tA?oaVZZiY=uqbEE`ii{Rj3LF+^$^m4CygXkBt)09x=iX$ z1**{AahcJd*+pNhclnj8&ZD!8^ONsMeG?#{Du*=zQn-ux5_C)uZ=$n%#v`7T6Qqso zSr;DrtMB)x5AUP*{~n`oX`Jr2yyDs4YQb8qwY#yqHb?2BDA?@b1hl(FWv6{Pr_C(0 zdiAp~+5n5*ae{0X>}xJ^1|}j(rl$8RpIFte4VHRde5u6iJTOAdh$+N|sz08`!7zVB zHUAj6_&gp_S9kC-5uQT(Y-8bOiaiDGr1y;sa%?aDo|pV~o_@_25i1fmbrz+`8ylB> zx;J2KoPZHO<^*g25rD!50Qe*A{gI9k;-oZiNZ9malKK-(E$1QuL;20e)9goYj*8XU z`Pq-igm=d>T^_f-OS--|58AX(kcQS9`M*E#Uc7d)PPcGKs?3t%qi02DEEvjS`?+*& zl9+z6u4j~zT#lKRzo}&C;el=-mpWMXKJRV`fZ+{e6YVNnuh*Wc!a+rgd%zE5Qsn zufIqq>F2C{!0N0-#hCsVRdVngq3=>=W9jNToH4&FK{|g!6T>10Z#bz`qa#sEB$62Axr`7JogVvhrr1 z%Ic3pUiGJ1NA}`*=e60F!{!HZ7V{bja8_v4ewA%np5-yQX9u|x29|7v%c!ro$SEkh zlTB&=6Vv9lWWu%6X)^SI4sC-m&A`Al<{Hmn_iTWE)l-5614Uh$!kzL1lbED&X;8eQ z0iDk0%&ibErGzU>y|F4ts?>K--VZ$#{>~3Tz8_f3KH_USTd-g1!c1IQ&)fM~ zfeY^;ef{ea3e1+6U#IuYmKK$3bU9^}#vyE(gZR>$ndZt%5#JI?V#Wsx((~*{bwWTY zwnrC!R-yMtD;|xt6(tuTOD{!a&}-A|2sEmsjmYnPcQW%g+_kNc(rrq)I3$uI^MC4_ z3YTkWJx|kmw@=UT?Tz|CP?4lKrU!-`1Kl#3Q#%vExxDb%lC8xlnat9w{PoUki_Ym* zy4vRFGVMOF-?o7tB`=v?dS$-$uGspTwN!XGWds!1adOoq5z7dx53Y2=|DVkEW@9*8KENm zSWBrm`&FfiMH!^WMQ=%G2!H6(fnj9_Kym}~q2E%nFa@9RS%S(b%Q#;1U}n4_?Sluf zkz!W>y(fkas?_%s+F!kKI^xs}*#ac$+3TXwOCa=NRD-w5fj7JWmj_B49Q9 z0-QhTFr57Mr0;x#$EGLWS*hTI^(NQ-UAc_;%YoSREA%V(bvAwWiJza^ zbh^l|i2E?YV$5h0?QQebCz1iWBAQO&-!oP|LQW@M!!+NuRnhQCi!M=}k-n?nx6-q~ zEgB#aBm=RTMW$w(a?M)QH@$-+>)ek>=Dnp$u6jFG@KbyoB)yh7(gQO$oXzH*73Qd8 zxBClWyB&$ve^u?_^Z^JrUwj-xt7KLVYJV3`+bE6(oEUJ@XG*nNOIvmQ|ApiLK99G_qnSdB^0m^GKf@mt~c!us?ih#*vQ^oWnri{ zs85D%_~$AH?@ou)`RmBKtE$rCyXdp<3m+Ht?563Bfj!};4l81u)+d!gp4pQIBeSI* zb1_Z)_kcZKRR#%@G6tdq#VT&kdF#HETxImN&1=BK9pla4|F(wDaK?>~N$3E<6L6Z} zaN!4!I`AAhqkf@ORy38KHmNu4XjqAt=~*2_E7mnsmbSBT`S*L_0!6B)Rf`}6W7S+y z(w>Tm{+wofh5cEw{#T*cdIyJ%Zbj<_UWVPPZo@^qz5MDGV;VbAPMx-vDBo`<{YYJE z%N0eXpB25SV-9dyYmZazH7({x^PVTQ(kFWwqt^aLUi?Sbqd9`3BIj3eR5lMM=MxuO z!d#DoYHF${$oDQ7u9>UR%!>v0^nw79(rhHHCowFqcjOqw;Kn|;=#VqMjlznX1ZGrwM>{9X@%JrRK65-Xy0 z+S+=1dxwXIr>Cb|4qG}d5Gl0Ga6@_KDgc1U{*{cR+PkT(q@b8ZWEAp<^;KxYz&b7q z%ig&V3$=bkeZuTSr#rA9n&#~K=H`ukls8tq6{dV}!gV8M)(43H3B?nekxu0%Lsi)6TQ7xnF`9ZLyX?ZAp3q0p34Z zzensQvmpIVRr|$3u{TK*X45%k^ec#O_VGe7T)5hl&-F`kGmN9Ut@oC*ccb~Cy36}( zm!!d^9Mv*szYIpjbC!BdY6Q&^nDM(imA}VPR@Dua#%@lwtd*qNbM0@N&Be7VU=3J> zGglwVbj_*-Y@F>=EatO|*cF8V$4|uIb_3XJ?(T^j?rMP&TvuOBS}fT>VxGzr?muFA zIPm8eu5fg{u;qTttlXBGnd~0EgJI3PkQn0G*hrC`V)F3SxQBTC&A>3DYJJ0m`-4AW z`!s{Y=H- zax1z1hP9&jvtS31BeN-I7w}ntamWKl`_t&*p%Jy`AJk1PDTTjf#=Sz@@f3}DVI4xv ztkjaKR{liGno1CnEJy#M#`w)#Fc}t|NAE>*fu~Vqfx)gn?t3&g3VZp+pSzTU z)N$Qt!HG0MU8vz+6ctKI#|i|3M_>%2JYhw(`Up=K0(FDNeVR@-x<9;m;kBGq`l3H|q+c1B&|_Mha>d#Y0)3 zKJ+3m6P~}~LpgpFo^14*$C%?YdHa3BmjgS*Syofa)xDD{I{Tz8rdeDDa6_48ERUye zFLOVKGDwp>3tD&_NzLybPO&^)|6Q1IE+E<@ypL%db>IiJe{Hw2sy*k__@mU1*~F+3 zZpLAnsG#sxSE4l>VrUM;X9SvZIGFZ5<9zPi^~Ev`7FQ@;s1-Sm0{R;%)geV3A-wA0 z^zWezzJrqQbHYD`vy?)#;dVyllqv1t2G;%hU#^UJZLCmyx5lsBQvS+0=7H}WmO6_3 z_Z&?fTI{i9oUEMRdP934bq>D>8F?Z6UJQu{I$OgL-Ckuv*$NTW{Ik5S&jKBz;RSL_ z&A-G36cjTro4#{|ITm(<&TJDW{m1p=npM?V64-sezXvdmF@LZ|z#*o~x)1nnU*MKe zsbOzd;kGr-R#ad1sOBS}xb!9gR+*?HKl6Qa?b2vHq>hc*P|^*E!i_t^c(`wqA^k}n zc#1bpDx@uu-l%Ug#_6z};-0LL(`Z-QitdvzuOlbB(ZDqqTwSob>F(OL+|0fX=(qJi z4#}5FSNx~tr2W7%_{V(O0o97wuk-3bbsjz?%P0AmH#r-)7RK{t1F+XZ3r!0w{-hs-kmZM@>FZp1twEWcMp>}-_rLOXf zJ{dzVra{SC+%xN6i9}tzl4aFd(e+^V_niF5$k!i6W38sO58xXNZ9Uzq>8~F3*!5Pz z?Bi#KP_WuczbXge0=(WHR>94wSMRCqLxp@D@X0Etp3NnH;x*Et$w)3<%nZ-21>YZz zmr=!Ad0S6Bu&}10WX1W!EUYjxM-gxe9tBm@_{kN$_9KxreP2HV}&bv(;m=xpRwO>54 z_PlIg(Z0FQUFh55l6_6U+FUIH$}PmoL$d-PE5i4NS=4=QEt=s~XB8rOZGh&X2Kyw%py`%fQ%tNA&^ zRHTV{`Qbv6_ZPG|dt55M=}%8(M-_e#?F&7RzqdXbgF1>u+!%#l=>_ zHhTYvV%IwNy!QltlLZyilncZ5Ga~Ge1;4UTDc7BcL}L^5ul%S9A3v{GPj7e851dTp z_PR#p-Q*SKU#ySF?$G-439rbDwmCcxb2oaI<^U%RM#{5Q0@>*e+-N$r38n_$U0*8= z#w4AGCG#=`SNkqtkEqO2BvLWd`KE#CDwD1Hk$aTH$l-$r@La5|BQfIO%()+}5n~2M z)$12n>;>{Gmbu}bm)Z}>mR=%XQl`5*P<*FvI$^L&Xx^=l60q^xW#F~>H0!z65ozE~ zDF6pG!g)ahBbT^Bx7T(VKXoiwbIIvk) zv@NkP%_3%)sPUXCm^WmEnY@k^nT7RHSudGiu>~zSjlsk_1C3(5RmvhSAZdll*<=me4!s=Lc@Ta#Iw0}%6)b)X&(fGbgfxVVQVyl!@^(ll3N#jG%IT+w z7&XqaC)J5vSL~>zAwsgl*2ePpKBj35 zNPPG-aM@O@pdwX8X;~{Reyi(b1yd=cj*1(k7z?JmuB-fj8XD;{Ght@A`X{pI3bg3_`axreb*SjZlC$xJeOYs z$i&d}m}*zQR24N;z-Dr#RTcg|xg?{8Oy0l>G`c)8#rLzJ8JCUkioPJLYFqbX4HI2O zyjQ|da6A*^Q>q>nVP6-<3%Zwy1QS22+jVmX%tP?n=;2jiQ**JP&?>ZG9Yf$$FCf^* z5EubU_S$;VNqxpMcKBhZO*hy5kS~<5P|ibC?CRKo+dU3UJ{M3kcgefy{Gn6x#{-0y0v0v#a`!TziW;gNrGL+hC~}52G8BTtCC9T=htET z(l^I+8*sP#CN`X;#>06CK~6iUer~6A)_E*=)GTB~wc;Apl#=3gy-qi{^AI_v3nDJ% zuOqNnR>BzW7c&wZ!HV7@S>jXeM5*x0=onlrJ$P|*zIx;Cl`VW560%%toT(kv`HY%A za4fMqldrZy6tY+_W4;;b=O$dY@x`8o&eJA6!NZm}<*F?-=Fml-F1G;gx(AVnCSNzQuyHgch@<(*y; z`Eqb0v~FeZ2Wkj{csIvRLn{IrYtV)7a=jU)BSKPdU3N(5pNFc4O{W=hdd}&tkDebo z^9i7alu~53EJdqp)bJ4m$(c2WO#PYb4Fam!{h8Y*{eADI&-SgSIJ9-;qc&BWGMmLfG=`4Qh(%kAUC);n~yPwGmyCWqld+%dUs z*h>&tw+2cjD|>(7$vmreZ`UgY)*r<2Yg-)Qj;{Tgy>(PcHHS;%DYDx(!DEA`!8Ih? zap3;;1^=fkN+OEMwY<%4%S=XV4yYl+jeD1+P|k)<`onQl#Dy`Zutq}-S6dJXeT{D1 zvJ`Ut2}P0rkD?uGwJeC{@H zHBhbia~T;G%ekp#Ff`hnvt`Ha52p0ykvE-*1l5LkZEf#Qk>g*T@IV=L45p-#$nA@1 zT6Aj#%tVQUnd%vX=WICjQsq8|_iy8*pTvW&RFS@rplsWWWAXkGW*bg*Iwp`SN<{%& zrQ^!h2(OSHC`>RLXQ**Ay}QV)AR$jNrD`%gWPW735jIPlrO`_F>2` zUI3CKoF|`-3}{g(;9;N#j3B2>-X_U+)!u4jg0gjLdOWm>mYV-Cn&^lqr-l{P@@P zp)vz5mw&V=jB(#JMj+C7Xb`MCBnW(TJRll63EcdmDVY|#+ZXte+CdrLykKtnX~Jo%F~b!U+wLU``_ zED*rkabomv2gZN8{d0XQhWD=j0x`%dL?GoO`1YR*VYlmG2vRQ`ADDRlLG)SGiPTjdkYxnJ3HGq;J@C6zyB%wOEAED#30{4W_Zd+ VgD%UBfO3%|IQR*%>Ui#0{{;}HCb$3q delta 8681 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 Date: Wed, 25 Sep 2024 14:54:49 +0100 Subject: [PATCH 36/88] fix ecall --- rtl/cpu/cpu.v | 13 ++++++++++--- sim/cpu.v | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index 2cdd78f..611f0ed 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -36,6 +36,8 @@ reg[31:0] read_data; wire [6:0] opcode = instruction[6:0]; wire [2:0] funct3 = instruction[14:12]; +wire instruction_is_ecall = instruction == {{12'b0}, {5'b0}, {FUNCT3_PRIV}, {5'b0}, {OPCODE_SYSTEM}}; + reg pc_load; reg pc_count; reg[31:0] pc_value; @@ -166,7 +168,7 @@ always @(posedge(clk_i)) begin STATE_REG_READ: begin state <= STATE_EXECUTE; - if(opcode == OPCODE_SYSTEM) begin + if(opcode == OPCODE_SYSTEM && funct3 != FUNCT3_PRIV) begin case(csr_address) CSR_MSTATUS: csr_read_value <= mstatus; CSR_MIE: csr_read_value <= mie; @@ -212,7 +214,7 @@ always @(posedge(clk_i)) begin // MPIE mstatus[7] <= 1; end - else case(csr_address) + else if (!instruction_is_ecall) case(csr_address) CSR_MSTATUS: mstatus <= alu_out_r; CSR_MIE: mie <= alu_out_r; CSR_MEPC: mepc <= alu_out_r; @@ -338,7 +340,8 @@ always @(*) begin end if((timer_interrupt && timer_interrupt_enable) - || (external_interrupt && external_interrupt_enable)) begin + || (external_interrupt && external_interrupt_enable) + || instruction_is_ecall) begin // Prevent memory writes if interrupted. This is the only side effect // of the instruction, so this effectively interrupts the instruction, // and it can be restarted after handling the interrupt. @@ -353,6 +356,10 @@ always @(*) begin pc_value = TRAP_PC; pc_load = 1; + if(instruction_is_ecall) begin + mcause_ = {1'b0, 31'd11}; + end + if(timer_interrupt) begin mcause_ = {1'b1, 31'd7}; end diff --git a/sim/cpu.v b/sim/cpu.v index b140f5b..48be7e8 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -123,7 +123,7 @@ always begin end always begin - #50_000_000 btn <= !btn; + #100_000_000 btn <= !btn; end initial begin From b8915cf7a2eb25f629f8fe830a9dcbd8f3ed2cf0 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 26 Sep 2024 14:20:20 +0100 Subject: [PATCH 37/88] create flash --- rtl/soc/flash.v | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 rtl/soc/flash.v diff --git a/rtl/soc/flash.v b/rtl/soc/flash.v new file mode 100644 index 0000000..13e61e6 --- /dev/null +++ b/rtl/soc/flash.v @@ -0,0 +1,27 @@ +`default_nettype none + +/* 32-bit * 16K word (64KByte) memory */ +module flash #( + parameter integer BASE_ADDRESS = 0 +) ( + input wire clk_i, + input wire rst_i, + input wire stb_i, + input wire cyc_i, + input wire [31:0] adr_i, + input wire [3:0] sel_i, + input wire [31:0] dat_i, + output wire [31:0] dat_o, + input wire we_i, + output reg ack_o, + output reg err_o, + output reg rty_o +); + + +// TODO: connect to the hard SPI controller +// Probably need a reset output signal that prevents the SoC booting while the +// SPI hardware is initialised. + + +endmodule From 3106e6a2b94d6a48739777296df4ed325d80a566 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Tue, 1 Oct 2024 13:20:02 +0100 Subject: [PATCH 38/88] WIP set up flash bootloader ROM --- boot_fw/CMakeLists.txt | 20 ++++++ boot_fw/TC-crush.cmake | 17 +++++ boot_fw/boot.S | 144 +++++++++++++++++++++++++++++++++++++++++ boot_fw/crush-boot.ld | 38 +++++++++++ 4 files changed, 219 insertions(+) create mode 100644 boot_fw/CMakeLists.txt create mode 100644 boot_fw/TC-crush.cmake create mode 100644 boot_fw/boot.S create mode 100644 boot_fw/crush-boot.ld diff --git a/boot_fw/CMakeLists.txt b/boot_fw/CMakeLists.txt new file mode 100644 index 0000000..e062157 --- /dev/null +++ b/boot_fw/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.24 FATAL_ERROR) + +project(crush-boot C ASM) + +add_executable(crush-boot) +target_sources(crush-boot PRIVATE boot.S) + +target_link_options(crush-boot PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/crush-boot.ld) +set_target_properties(crush-boot PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/crush-boot.ld) + +string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) +find_program(objcopy_program ${objcopy_name} REQUIRED) +add_custom_command(TARGET crush-boot POST_BUILD + COMMAND ${objcopy_program} -O binary crush-boot crush-boot.bin + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +add_custom_command(TARGET crush-boot POST_BUILD + COMMAND ${objcopy_program} --verilog-data-width 4 -O verilog crush-boot crush-boot.data + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) diff --git a/boot_fw/TC-crush.cmake b/boot_fw/TC-crush.cmake new file mode 100644 index 0000000..dd3584b --- /dev/null +++ b/boot_fw/TC-crush.cmake @@ -0,0 +1,17 @@ +# https://www.vinnie.work/blog/2020-11-17-cmake-eval + +set(CMAKE_SYSTEM_NAME Generic) + +find_program(COMPILER_PATH + NAMES + # ubuntu and debian + riscv32-unknown-elf-gcc + riscv64-unknown-elf-gcc + # arch linux + riscv64-elf-gcc + REQUIRED) +get_filename_component(COMPILER_NAME ${COMPILER_PATH} NAME) +set(CMAKE_C_COMPILER ${COMPILER_NAME}) + +set(CMAKE_C_FLAGS "-nostartfiles -nostdlib -march=rv32i -mabi=ilp32") +set(CMAKE_ASM_FLAGS "-nostartfiles -nostdlib -march=rv32i -mabi=ilp32") diff --git a/boot_fw/boot.S b/boot_fw/boot.S new file mode 100644 index 0000000..f197af3 --- /dev/null +++ b/boot_fw/boot.S @@ -0,0 +1,144 @@ +/* + * boot.S + * + * SPI boot code + * + * Copyright (C) 2020 Sylvain Munaut + * SPDX-License-Identifier: MIT + */ + +#ifndef APP_FLASH_ADDR +#define APP_FLASH_ADDR 0x00100000 +#endif + +#ifndef APP_SRAM_ADDR +#define APP_SRAM_ADDR 0x00020000 +#endif + +#ifndef APP_SIZE +#define APP_SIZE 0x00010000 +#endif + + .section .text.start + .global _start +_start: + // SPI init + jal spi_init + + // Read from flash to SRAM + li a0, APP_SRAM_ADDR + li a1, APP_SIZE + li a2, APP_FLASH_ADDR + jal spi_flash_read + + // Setup reboot code + li t0, 0x0002006f + sw t0, 0(zero) + + // Jump to main code + j APP_SRAM_ADDR + + + .equ SPI_BASE, 0x82000000 + .equ SPICR0, 4 * 0x08 + .equ SPICR1, 4 * 0x09 + .equ SPICR2, 4 * 0x0a + .equ SPIBR, 4 * 0x0b + .equ SPISR, 4 * 0x0c + .equ SPITXDR, 4 * 0x0d + .equ SPIRXDR, 4 * 0x0e + .equ SPICSR, 4 * 0x0f + + +spi_init: + li a0, SPI_BASE + + li a1, 0xff + sw a1, SPICR0(a0) + + li a1, 0x80 + sw a1, SPICR1(a0) + + li a1, 0xc0 + sw a1, SPICR2(a0) + + li a1, 0x03 + sw a1, SPIBR(a0) + + li a1, 0x0f + sw a1, SPICSR(a0) + + ret + + +// Params: +// a0 - destination pointer +// a1 - length (bytes) +// a2 - flash offset +// + +spi_flash_read: + // Save params + mv s0, a0 + mv s1, a1 + mv s2, ra + + // Setup CS + li t0, SPI_BASE + li t1, 0x0e + sw t1, SPICSR(t0) + + // Send command + li a0, 0x03 + jal _spi_do_one + + srli a0, a2, 16 + and a0, a0, 0xff + jal _spi_do_one + + srli a0, a2, 8 + and a0, a0, 0xff + jal _spi_do_one + + and a0, a2, 0xff + jal _spi_do_one + + // Read loop +_spi_loop: + li a0, 0x00 + jal _spi_do_one + sb a0, 0(s0) + addi s0, s0, 1 + addi s1, s1, -1 + bne s1, zero, _spi_loop + + // Release CS + li t0, SPI_BASE + li t1, 0x0f + sw t1, SPICSR(t0) + + // Done + jr s2 + + +// Params: a0 - Data to TX +// Returns: a0 - RX data +// Clobbers t0, t1 +_spi_do_one: + li t0, SPI_BASE + li t1, 0x08 + + // Write TX data + sw a0, SPITXDR(t0) + + // Wait for RXRDY +1: + lw a0, SPISR(t0) + and a0, a0, t1 + bne a0, t1, 1b + + // Read RX data + lw a0, SPIRXDR(t0) + + // Done + ret diff --git a/boot_fw/crush-boot.ld b/boot_fw/crush-boot.ld new file mode 100644 index 0000000..eec4140 --- /dev/null +++ b/boot_fw/crush-boot.ld @@ -0,0 +1,38 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(start) + +MEMORY +{ + mem (rwx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 +} + +SECTIONS +{ + .mem : { + . = ALIGN(4); + KEEP(*(.start)) + *(.text .text.*) + *(.rodata .rodata*) + . = ALIGN(4); + *(.data .data.*); + } > mem + + .bss (NOLOAD) : { + . = ALIGN(4); + bss_start = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(4); + bss_end = .; + } > mem + + .stack : { + . = 1K; /* stack size */ + /* Calling conventions require 16 byte aligned stack pointer + * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + */ + . = ALIGN(16); + stack_start = .; + } > mem +} + From eb3c0b84bfedcf5799aa01535790a84ebd4a753a Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Tue, 1 Oct 2024 13:24:40 +0100 Subject: [PATCH 39/88] fix linker script --- boot_fw/crush-boot.ld | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/boot_fw/crush-boot.ld b/boot_fw/crush-boot.ld index eec4140..62e4537 100644 --- a/boot_fw/crush-boot.ld +++ b/boot_fw/crush-boot.ld @@ -1,38 +1,17 @@ OUTPUT_ARCH( "riscv" ) -ENTRY(start) +ENTRY(_start) MEMORY { - mem (rwx): ORIGIN = 0x10000000, LENGTH = 0x800 * 4 + rom (rx): ORIGIN = 0x00000000, LENGTH = 256 } SECTIONS { - .mem : { + .rom : { . = ALIGN(4); - KEEP(*(.start)) + KEEP(*(.text.start)) *(.text .text.*) - *(.rodata .rodata*) - . = ALIGN(4); - *(.data .data.*); - } > mem - - .bss (NOLOAD) : { - . = ALIGN(4); - bss_start = .; - *(.bss .bss.*) - *(COMMON) - . = ALIGN(4); - bss_end = .; - } > mem - - .stack : { - . = 1K; /* stack size */ - /* Calling conventions require 16 byte aligned stack pointer - * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc - */ - . = ALIGN(16); - stack_start = .; - } > mem + } > rom } From 7759a01dfc012ae2cd465fb98411dcd40ce65f50 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Tue, 1 Oct 2024 15:20:24 +0100 Subject: [PATCH 40/88] WIP set up flash loading --- boot_fw/boot.S | 10 +++------- freertos/app/crush.ld | 9 +++------ freertos/app/src/start.c | 22 ---------------------- sim/cpu.v | 28 ++++++++-------------------- sim/flash_emulator.v | 28 ++++++++++++++-------------- 5 files changed, 28 insertions(+), 69 deletions(-) diff --git a/boot_fw/boot.S b/boot_fw/boot.S index f197af3..42b308d 100644 --- a/boot_fw/boot.S +++ b/boot_fw/boot.S @@ -12,11 +12,11 @@ #endif #ifndef APP_SRAM_ADDR -#define APP_SRAM_ADDR 0x00020000 +#define APP_SRAM_ADDR 0x20000000 #endif #ifndef APP_SIZE -#define APP_SIZE 0x00010000 +#define APP_SIZE 0x10000 #endif .section .text.start @@ -31,15 +31,11 @@ _start: li a2, APP_FLASH_ADDR jal spi_flash_read - // Setup reboot code - li t0, 0x0002006f - sw t0, 0(zero) - // Jump to main code j APP_SRAM_ADDR - .equ SPI_BASE, 0x82000000 + .equ SPI_BASE, 0x50000000 .equ SPICR0, 4 * 0x08 .equ SPICR1, 4 * 0x09 .equ SPICR2, 4 * 0x0a diff --git a/freertos/app/crush.ld b/freertos/app/crush.ld index a2cdf79..21f1ffb 100644 --- a/freertos/app/crush.ld +++ b/freertos/app/crush.ld @@ -3,13 +3,12 @@ ENTRY(start) MEMORY { - flash (rx): ORIGIN = 0x10000000, LENGTH = 0x10000 ram (rwx): ORIGIN = 0x20000000, LENGTH = 0x10000 } SECTIONS { - .flash : { + .text : { . = ALIGN(4); KEEP(*(.start)) . = 0x100; @@ -17,7 +16,7 @@ SECTIONS *(.text .text.*) *(.rodata .rodata* .srodata .srodata.*) . = ALIGN(4); - } > flash + } > ram .data : { . = ALIGN(4); @@ -25,9 +24,7 @@ SECTIONS *(.data .data.* .sdata .sdata.*); . = ALIGN(4); __data_end = .; - } > ram AT> flash - - __flash_data_start = LOADADDR(.data); + } > ram .bss (NOLOAD) : { . = ALIGN(4); diff --git a/freertos/app/src/start.c b/freertos/app/src/start.c index 20f99ee..f09ac88 100644 --- a/freertos/app/src/start.c +++ b/freertos/app/src/start.c @@ -12,16 +12,6 @@ extern int bss_start[0]; /** The end of the region in RAM to be zero initialised */ extern int bss_end[0]; -/** The start of the region in flash containing the program data */ -extern int __flash_data_start[0]; -/** The end of the region in flash containing the program data */ -extern int __flash_data_end[0]; - -/** The start of the region in RAM where program data is copied */ -extern int __data_start[0]; -/** The end of the region in RAM where program data is copied*/ -extern int __data_end[0]; - /** * @} */ @@ -36,18 +26,6 @@ int main(void); */ void c_start(void) { - { - int *src = __flash_data_start; - int *dst = __data_start; - - while(dst < __data_end) { - *dst = *src; - - dst++; - src++; - } - } - for(int *i = bss_start; i < bss_end; i++) { *i = 0; diff --git a/sim/cpu.v b/sim/cpu.v index 48be7e8..b406a05 100644 --- a/sim/cpu.v +++ b/sim/cpu.v @@ -1,6 +1,10 @@ -/* This file implements a test that is able to execute programs stored on the - * host file system. It can be used along with RISCOF - The RISC-V - * Compatibility Framework. +/* This file implements a test that simulates the CPU configured with interrupts. + * + * It is capable of running the FreeRTOS demo app. + * + * The initial configuration of the simulation is equivalent to the SoC after it + * has been booted from flash by the boot ROM. The simulation skips the loading, + * and starts up with the program already stored in memory. */ `default_nettype none @@ -26,7 +30,7 @@ wire rty_i = 0; wire timer_interrupt; -cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( +cpu #(.INITIAL_PC('h2000_0000), .TRAP_PC('h2000_0100)) dut ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), @@ -59,22 +63,6 @@ flash_emulator #(.BASE_ADDRESS('h1000_0000), .SIZE('h1_0000)) flash_emulator ( .rty_o(rty_i) ); -wire memory_ack_o; -memory_ice40_spram_wb #(.BASE_ADDRESS('h2000_0000)) memory ( - .clk_i(clk), - .rst_i(reset), - .stb_i(stb_o), - .cyc_i(cyc_o), - .adr_i(adr_o), - .sel_i(sel_o), - .dat_i(dat_o), - .dat_o(dat_i), - .we_i(we_o), - .ack_o(memory_ack_o), - .err_o(err_i), - .rty_o(rty_i) -); - wire mtimer_ack_o; mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( .clk_i(clk), diff --git a/sim/flash_emulator.v b/sim/flash_emulator.v index cfb83bf..8d35622 100644 --- a/sim/flash_emulator.v +++ b/sim/flash_emulator.v @@ -21,10 +21,12 @@ module flash_emulator #( output reg rty_o ); -reg [31:0] data; -assign dat_o = ack_o ? data : 32'hzzzz_zzzz; +reg[31:0] mem[SIZE]; + + wire[31:0] mask = {{8{sel_i[3]}}, {8{sel_i[2]}}, {8{sel_i[1]}}, {8{sel_i[0]}}}; + wire[31:0] memory_address = (adr_i - BASE_ADDRESS) >> 2; + wire[31:0] value = mem[memory_address]; -reg[31:0] flash[SIZE]; wire addressed = (adr_i >= BASE_ADDRESS) & (adr_i < (BASE_ADDRESS + SIZE)); initial begin @@ -36,7 +38,7 @@ initial begin $display("Reading flash contents from %s", binary_path); file = $fopen(binary_path, "rb"); - length = $fread(flash, file); + length = $fread(mem, file); $fclose(file); $display("Read %0d bytes", length); @@ -51,20 +53,18 @@ always @(posedge clk_i) begin ack_o <= 0; err_o <= 0; rty_o <= 0; - data <= 32'h0000_0000; + dat_o <= 32'hzzzz_zzzz; - if (stb_i & cyc_i & !we_i & !ack_o & addressed) begin - ack_o <= 1; + if (stb_i & cyc_i & !ack_o & addressed) begin + ack_o <= 1; + end - read_data = flash[(adr_i - BASE_ADDRESS) >> 2]; - data <= {{read_data[ 7: 0]}, - {read_data[15: 8]}, - {read_data[23:16]}, - {read_data[31:24]}}; + if (stb_i & cyc_i & addressed & we_i) begin + mem[memory_address] <= (value & ~mask) | (dat_i & mask); end - if (stb_i & cyc_i & we_i & addressed) begin - $fatal(1, "Flash is not writable"); + if (stb_i & cyc_i & addressed & !we_i) begin + dat_o <= mem[memory_address]; end end From c2cd6c9a0ede1f4d5eda70dc61ff21c255d9c23f Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 2 Oct 2024 20:07:35 +0100 Subject: [PATCH 41/88] prepare for merge --- crush.core | 15 +++++++++++++++ run_sim.sh | 2 +- sim/{cpu.v => cpu_freertos_tb.v} | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) rename sim/{cpu.v => cpu_freertos_tb.v} (99%) diff --git a/crush.core b/crush.core index 685a2ab..59f5886 100644 --- a/crush.core +++ b/crush.core @@ -57,6 +57,13 @@ filesets: - sim/flash_emulator.v file_type: systemVerilogSource + sim_cpu_freertos: + files: + - sim/control.v + - sim/cpu_freertos_tb.v + - sim/flash_emulator.v + file_type: systemVerilogSource + sim_common: files: - sim/fatal_assert.vh: @@ -176,6 +183,14 @@ targets: toplevel: cpu_tb default_tool: icarus + sim_cpu_freertos: + <<: *default + filesets_append: + - sim_common + - sim_cpu_freertos + toplevel: cpu_freertos_tb + default_tool: icarus + sim_mtimer: <<: *default filesets_append: diff --git a/run_sim.sh b/run_sim.sh index 2857cf6..93f44e3 100755 --- a/run_sim.sh +++ b/run_sim.sh @@ -1,2 +1,2 @@ cmake --build ./freertos/app/build -fusesoc run --target sim_cpu --build --resolve-env-vars-early crush && vvp -n build/crush_0.0.1/sim_cpu-icarus/crush_0.0.1 +BINARY_PATH=freertos/app/build/crush_freertos.bin +fusesoc run --target sim_cpu_freertos --build --resolve-env-vars-early crush && vvp -n build/crush_0.0.1/sim_cpu_freertos-icarus/crush_0.0.1 +BINARY_PATH=freertos/app/build/crush_freertos.bin diff --git a/sim/cpu.v b/sim/cpu_freertos_tb.v similarity index 99% rename from sim/cpu.v rename to sim/cpu_freertos_tb.v index b406a05..d490501 100644 --- a/sim/cpu.v +++ b/sim/cpu_freertos_tb.v @@ -11,7 +11,7 @@ `timescale 1ns/1ps -module cpu_tb; +module cpu_freertos_tb; `include "params.vh" From 9466d5bd286f9cf6d06bb053a6be12094ab8c0a9 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 2 Oct 2024 20:55:44 +0100 Subject: [PATCH 42/88] fix bootloader build --- boot_fw/CMakeLists.txt | 4 ---- boot_fw/boot.S | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/boot_fw/CMakeLists.txt b/boot_fw/CMakeLists.txt index e062157..7362ccb 100644 --- a/boot_fw/CMakeLists.txt +++ b/boot_fw/CMakeLists.txt @@ -10,10 +10,6 @@ set_target_properties(crush-boot PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_ string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) find_program(objcopy_program ${objcopy_name} REQUIRED) -add_custom_command(TARGET crush-boot POST_BUILD - COMMAND ${objcopy_program} -O binary crush-boot crush-boot.bin - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ) add_custom_command(TARGET crush-boot POST_BUILD COMMAND ${objcopy_program} --verilog-data-width 4 -O verilog crush-boot crush-boot.data WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/boot_fw/boot.S b/boot_fw/boot.S index 42b308d..24c64d4 100644 --- a/boot_fw/boot.S +++ b/boot_fw/boot.S @@ -32,7 +32,8 @@ _start: jal spi_flash_read // Jump to main code - j APP_SRAM_ADDR + li t0, APP_SRAM_ADDR + jr t0 .equ SPI_BASE, 0x50000000 From dd14a1f236e41aecb80f4857612309e4c71b5eb2 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 2 Oct 2024 21:53:20 +0100 Subject: [PATCH 43/88] start implementing top level for freertos demo --- crush.core | 28 +++++++++-- rtl/cpu/mtimer.v | 3 +- rtl/soc/top_freertos.v | 107 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 rtl/soc/top_freertos.v diff --git a/crush.core b/crush.core index 5baf027..2ba158c 100644 --- a/crush.core +++ b/crush.core @@ -19,16 +19,28 @@ filesets: - rtl/soc/memory_infer.v: {file_type: systemVerilogSource} - rtl/soc/memory_ice40_spram.v - rtl/soc/memory_ice40_spram_wb.v - - rtl/soc/top.v - rtl/soc/gpio.v + file_type: verilogSource + + pcf: + files: + - data/icebreaker.pcf: {file_type: PCF} + + top_default: + files: + - rtl/soc/top.v - fw/binary/crush-blinky.data: file_type: user copyto: fw.data file_type: verilogSource - pcf: + top_freertos: files: - - data/icebreaker.pcf: {file_type: PCF} + - rtl/soc/top_freertos.v + - boot_fw/build/crush-boot.data: + file_type: user + copyto: boot.data + file_type: verilogSource sim_inst_immediate_decode: files: @@ -95,6 +107,7 @@ targets: default: &default filesets: - rtl + - top_default - pcf toplevel: top default_tool: icestorm @@ -111,6 +124,14 @@ targets: hooks: post_run: [iceprog_hint] + top_freertos: + <<: *default + filesets: + - rtl + - top_freertos + - pcf + toplevel: top_freertos + lint: default_tool : verilator filesets: @@ -200,6 +221,7 @@ targets: <<: *default filesets_append: - sim_top + - top_default toplevel: top_tb default_tool: icarus diff --git a/rtl/cpu/mtimer.v b/rtl/cpu/mtimer.v index 0fe456d..86ba6c8 100644 --- a/rtl/cpu/mtimer.v +++ b/rtl/cpu/mtimer.v @@ -51,7 +51,8 @@ module mtimer #( rty_o <= 0; if(rst_i) begin - for(int i = 0; i < 4; i++) mem[i] <= 0; + integer i; + for(i = 0; i < 4; i++) mem[i] <= 0; interrupt <= 0; end else begin {mem[1], mem[0]} <= mtime + 1; diff --git a/rtl/soc/top_freertos.v b/rtl/soc/top_freertos.v new file mode 100644 index 0000000..9a92fd7 --- /dev/null +++ b/rtl/soc/top_freertos.v @@ -0,0 +1,107 @@ +`default_nettype none + +module top_freertos ( + input wire CLK, + input wire BTN_N, + input wire BTN1, + output wire LED1, + output wire LED2 +); + +wire rst_i = !BTN_N; +wire clk = CLK; + +wire stb_o; +wire cyc_o; +wire[31:0] adr_o; +wire[3:0] sel_o; +wire[31:0] dat_i; +wire[31:0] dat_o; +wire we_o; +wire ack_i; +wire err_i; +wire rty_i; + +cpu #(.INITIAL_PC('h0000_0000), .TRAP_PC('h1000_0100)) dut ( + .clk_i(clk), + .dat_i(dat_i), + .dat_o(dat_o), + .rst_i(rst_i), + .ack_i(ack_i), + .err_i(err_i), + .rty_i(rty_i), + .stb_o(stb_o), + .cyc_o(cyc_o), + .adr_o(adr_o), + .sel_o(sel_o), + .we_o(we_o) +); + +wire boot_rom_ack_o; +wire boot_rom_rty_o; +wire boot_rom_err_o; + memory_infer #( + .BASE_ADDRESS('h0000_0000), + .SIZE(256), + .READMEMH_FILE("boot.data") + ) boot_rom ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i (we_o), + .ack_o(boot_rom_ack_o), + .err_o(boot_rom_err_o), + .rty_o(boot_rom_rty_o) + ); + +wire ram_ack_o; +wire ram_rty_o; +wire ram_err_o; + memory_ice40_spram_wb #( + .BASE_ADDRESS('h1000_0000), + ) ram ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i (we_o), + .ack_o(ram_ack_o), + .err_o(ram_err_o), + .rty_o(ram_rty_o) + ); + +wire gpio_ack_o; +wire gpio_rty_o; +wire gpio_err_o; +wire [5:0] unused; +gpio #(.BASE_ADDRESS('h4000_0000)) gpio ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(gpio_ack_o), + .err_o(gpio_err_o), + .rty_o(gpio_rty_o), + .pin_input({{7{1'b0}}, BTN1}), + .pin_output({unused, LED2, LED1}) +); + +assign ack_i = boot_rom_ack_o | ram_ack_o | gpio_ack_o; +assign err_i = boot_rom_err_o | ram_err_o | gpio_err_o; +assign rty_i = boot_rom_rty_o | ram_rty_o | gpio_rty_o; + +endmodule From cfe9e5c80ed10add1e34c47b15c4ea94450bc131 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 2 Oct 2024 23:26:33 +0100 Subject: [PATCH 44/88] WIP integrate SPI boot loading --- crush.core | 1 + rtl/soc/spi.v | 123 +++++++++++++++++++++++++++++++++++++++++ rtl/soc/top_freertos.v | 34 ++++++++++-- 3 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 rtl/soc/spi.v diff --git a/crush.core b/crush.core index 2ba158c..6b561ea 100644 --- a/crush.core +++ b/crush.core @@ -20,6 +20,7 @@ filesets: - rtl/soc/memory_ice40_spram.v - rtl/soc/memory_ice40_spram_wb.v - rtl/soc/gpio.v + - rtl/soc/spi.v: {file_type: systemVerilogSource} file_type: verilogSource pcf: diff --git a/rtl/soc/spi.v b/rtl/soc/spi.v new file mode 100644 index 0000000..641a19e --- /dev/null +++ b/rtl/soc/spi.v @@ -0,0 +1,123 @@ +`default_nettype none + +/* + * Interface to hard SPI unit 0. + */ +module spi #( + parameter integer BASE_ADDRESS +) ( + input wire clk_i, + // The memory we are trying to infer can not be reset + // verilator lint_off UNUSEDSIGNAL + input wire rst_i, + // verilator lint_on UNUSEDSIGNAL + input wire stb_i, + input wire cyc_i, + input wire [31:0] adr_i, + input wire [3:0] sel_i, + input wire [31:0] dat_i, + output wire [31:0] dat_o, + input wire we_i, + output reg ack_o, + output reg err_o, + output reg rty_o, + // Flash SPI interface + inout wire flash_clk, + inout wire flash_miso, + inout wire flash_mosi, + output wire flash_cs_n, +); + reg [31:0] data = {24'h0, spi_sbdato}; + + assign ack_o = spi_sbacko; + + assign dat_o = ack_o ? data : 32'hzzzz_zzzz; + + wire addressed = (adr_i >= BASE_ADDRESS) & (adr_i < BASE_ADDRESS + 4 * 32'h10); + +wire spi_sbclki = clk_i; +wire spi_sbrwi = we_i; +wire spi_sbstbi = addressed & cyc_i & stb_i; +wire [7:0] spi_sbadri = {4'b0010, adr_i[3+2:2]}; +wire [7:0] spi_sbdati = dat_i[7:0]; +wire spi_mi; +wire spi_si; +wire spi_scki; +wire spi_scsni = 1; +wire [7:0] spi_sbdato; +wire spi_sbacko; +wire spi_spiirq; +wire spi_spiwkup; +wire spi_so; +wire spi_soe; +wire spi_mo; +wire spi_moe; +wire spi_scko; +wire spi_sckoe; +wire [3:0] spi_mcsno; +wire [3:0] spi_mcsnoe; + +SB_SPI #(.BUS_ADDR74("0b0010")) spi ( + .SBCLKI(spi_sbclki), + .SBRWI(spi_sbrwi), + .SBSTBI(spi_sbstbi), + .SBADRI7(spi_sbadri[7]), + .SBADRI6(spi_sbadri[6]), + .SBADRI5(spi_sbadri[5]), + .SBADRI4(spi_sbadri[4]), + .SBADRI3(spi_sbadri[3]), + .SBADRI2(spi_sbadri[2]), + .SBADRI1(spi_sbadri[1]), + .SBADRI0(spi_sbadri[0]), + .SBDATI7(spi_sbdati[7]), + .SBDATI6(spi_sbdati[6]), + .SBDATI5(spi_sbdati[5]), + .SBDATI4(spi_sbdati[4]), + .SBDATI3(spi_sbdati[3]), + .SBDATI2(spi_sbdati[2]), + .SBDATI1(spi_sbdati[1]), + .SBDATI0(spi_sbdati[0]), + .MI(spi_mi), + .SI(spi_si), + .SCKI(spi_scki), + .SCSNI(spi_scsni), + .SBDATO7(spi_sbdato[7]), + .SBDATO6(spi_sbdato[6]), + .SBDATO5(spi_sbdato[5]), + .SBDATO4(spi_sbdato[4]), + .SBDATO3(spi_sbdato[3]), + .SBDATO2(spi_sbdato[2]), + .SBDATO1(spi_sbdato[1]), + .SBDATO0(spi_sbdato[0]), + .SBACKO(spi_sbacko), + .SPIIRQ(spi_spiirq), + .SPIWKUP(spi_spiwkup), + .SO(spi_so), + .SOE(spi_soe), + .MO(spi_mo), + .MOE(spi_moe), + .SCKO(spi_scko), + .SCKOE(spi_sckoe), + .MCSNO3(spi_mcsno[3]), + .MCSNO2(spi_mcsno[2]), + .MCSNO1(spi_mcsno[1]), + .MCSNO0(spi_mcsno[0]), + .MCSNOE3(spi_mcsnoe[3]), + .MCSNOE2(spi_mcsnoe[2]), + .MCSNOE1(spi_mcsnoe[1]), + .MCSNOE0(spi_mcsnoe[0]) +); + + SB_IO #( + .PIN_TYPE(6'b101001), + .PULLUP(1'b1) + ) io[2:0] ( + .PACKAGE_PIN ({flash_mosi, flash_miso, flash_clk }), + .OUTPUT_ENABLE({spi_moe, spi_soe, spi_sckoe}), + .D_OUT_0 ({spi_mo, spi_so, spi_scko }), + .D_IN_0 ({spi_si, spi_mi, spi_scki }) + ); + + assign flash_cs_n = spi_mcsno[0]; + +endmodule diff --git a/rtl/soc/top_freertos.v b/rtl/soc/top_freertos.v index 9a92fd7..72bc263 100644 --- a/rtl/soc/top_freertos.v +++ b/rtl/soc/top_freertos.v @@ -5,7 +5,11 @@ module top_freertos ( input wire BTN_N, input wire BTN1, output wire LED1, - output wire LED2 + output wire LED2, + inout wire FLASH_SCK, + inout wire FLASH_SSB, + inout wire FLASH_IO0, + inout wire FLASH_IO1 ); wire rst_i = !BTN_N; @@ -100,8 +104,30 @@ gpio #(.BASE_ADDRESS('h4000_0000)) gpio ( .pin_output({unused, LED2, LED1}) ); -assign ack_i = boot_rom_ack_o | ram_ack_o | gpio_ack_o; -assign err_i = boot_rom_err_o | ram_err_o | gpio_err_o; -assign rty_i = boot_rom_rty_o | ram_rty_o | gpio_rty_o; +wire spi_ack_o; +wire spi_rty_o; +wire spi_err_o; +spi #(.BASE_ADDRESS('h5000_0000)) spi ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(spi_ack_o), + .err_o(spi_err_o), + .rty_o(spi_rty_o), + .flash_clk(FLASH_SCK), + .flash_miso(FLASH_IO1), + .flash_mosi(FLASH_IO0), + .flash_cs_n(FLASH_SSB), +); + +assign ack_i = boot_rom_ack_o | ram_ack_o | gpio_ack_o | spi_ack_o; +assign err_i = boot_rom_err_o | ram_err_o | gpio_err_o | spi_err_o; +assign rty_i = boot_rom_rty_o | ram_rty_o | gpio_rty_o | spi_rty_o; endmodule From 395220ddb3fc7d4929e3f5235ad21a3ff4be6cea Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 3 Oct 2024 00:12:20 +0100 Subject: [PATCH 45/88] clean up some lints --- crush.core | 2 ++ rtl/soc/spi.v | 2 +- rtl/soc/top_freertos.v | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crush.core b/crush.core index 6b561ea..9bbcdc0 100644 --- a/crush.core +++ b/crush.core @@ -145,6 +145,8 @@ targets: - sim_cpu - sim_mtimer - sim_common + - top_default + - top_freertos tools: verilator: mode : lint-only diff --git a/rtl/soc/spi.v b/rtl/soc/spi.v index 641a19e..4389b1f 100644 --- a/rtl/soc/spi.v +++ b/rtl/soc/spi.v @@ -25,7 +25,7 @@ module spi #( inout wire flash_clk, inout wire flash_miso, inout wire flash_mosi, - output wire flash_cs_n, + output wire flash_cs_n ); reg [31:0] data = {24'h0, spi_sbdato}; diff --git a/rtl/soc/top_freertos.v b/rtl/soc/top_freertos.v index 72bc263..67e598a 100644 --- a/rtl/soc/top_freertos.v +++ b/rtl/soc/top_freertos.v @@ -67,7 +67,7 @@ wire ram_ack_o; wire ram_rty_o; wire ram_err_o; memory_ice40_spram_wb #( - .BASE_ADDRESS('h1000_0000), + .BASE_ADDRESS('h1000_0000) ) ram ( .clk_i(clk), .rst_i(rst_i), @@ -123,7 +123,7 @@ spi #(.BASE_ADDRESS('h5000_0000)) spi ( .flash_clk(FLASH_SCK), .flash_miso(FLASH_IO1), .flash_mosi(FLASH_IO0), - .flash_cs_n(FLASH_SSB), + .flash_cs_n(FLASH_SSB) ); assign ack_i = boot_rom_ack_o | ram_ack_o | gpio_ack_o | spi_ack_o; From 49ddfa213f40dd2e77a3940fe4d3bcf8ee20c3a1 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Wed, 22 Jan 2025 15:04:25 +0000 Subject: [PATCH 46/88] Replace hardware SPI with a soft SPI This is easier to debug with the help of a verilog flash emulator. There is no emulation available for the hardware SPI so we can't debug in a simulator. Now the FreeRTOS app is able to run on hardware and a full system simulation is also available running the same app. --- .gitignore | 1 + README.md | 61 + boot_fw/boot.S | 238 +- crush.core | 26 +- freertos/app/CMakeLists.txt | 7 +- freertos/app/src/hal.c | 2 +- requirements.txt | 4 +- rtl/cpu/mtimer.v | 2 +- rtl/soc/spi.v | 105 +- rtl/soc/top_freertos.v | 33 +- script/init.sh | 3 + sim/s25fl128s.v | 8077 +++++++++++++++++++++++++++++++++ sim/top_freertos_tb.v | 68 + tools/freertos_top.gtkw | 60 + tools/freertos_top_debug.gtkw | 40 + 15 files changed, 8528 insertions(+), 199 deletions(-) create mode 100644 sim/s25fl128s.v create mode 100644 sim/top_freertos_tb.v create mode 100644 tools/freertos_top.gtkw create mode 100644 tools/freertos_top_debug.gtkw diff --git a/.gitignore b/.gitignore index 9d812a3..406d9cf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build fusesoc.conf +fusesoc_libraries diff --git a/README.md b/README.md index ebcdbd4..87561b4 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,64 @@ Goals: | [verible](https://github.com/chipsalliance/verible) | Standard LSP linter that can integrate with most text editors. | | [FuseSoC](https://github.com/olofk/fusesoc) | Build tool that simplifies running the testbenches and synthesis tools. | | [RISCOF, a RISC-V Architectural Test Framework](https://github.com/riscv-software-src/riscof) | The design passes all tests provided by RISCOF. See the `tools/compliance` folder. | + +## Demo SoCs + +### Basic Configuration (module top) + +#### Boot process + +All firmware executes directly from configurable block RAM. There is no support +for booting from flash. The block RAM stores both the executable code and the +system RAM. + +#### Vectors + +| Vector | Address | +|--------|-------------| +| Reset | 0x1000_0000 | + + +#### Memory Map + +| Address | Size (bytes) | Description | +|-------------|--------------|-------------| +| 0x1000_0000 | 8192 | Block RAM | +| 0x4000_0000 | | GPIO | + +### RTOS configuration (module top_freertos) + +#### Boot process + +The first stage bootloader stored in block RAM copies program data from flash to +RAM, then jumps to the "Boot entry" vector at the top of RAM (0x1000_0000). +After the bootloader completes, the application runs from SPRAM and the flash is +not used any more. + +#### Vectors + +| Vector | Address | +|----------------------|-------------| +| Reset | 0x0000_0000 | +| Bootloader app entry | 0x1000_0000 | +| Interrupt | 0x1000_0100 | + +#### Memory Map + +| Address | Size (bytes) | Description | +|-------------|--------------|----------------| +| 0x0000_0000 | 1024 | Boot block RAM | +| 0x1000_0000 | 65536 | SPRAM | +| 0x3000_0000 | | mtimer | +| 0x4000_0000 | | GPIO | +| 0x5000_0000 | | SPI | + +## References + +The SPI flash bootloader is based on the following open source libraries: + +https://github.com/no2fpga/no2bootloader + +https://github.com/chipsalliance/VeeRwolf + +https://github.com/olofk/simple_spi diff --git a/boot_fw/boot.S b/boot_fw/boot.S index 24c64d4..3036440 100644 --- a/boot_fw/boot.S +++ b/boot_fw/boot.S @@ -2,140 +2,164 @@ * boot.S * * SPI boot code - * - * Copyright (C) 2020 Sylvain Munaut - * SPDX-License-Identifier: MIT */ #ifndef APP_FLASH_ADDR -#define APP_FLASH_ADDR 0x00100000 +#define APP_FLASH_ADDR 0x20000 #endif #ifndef APP_SRAM_ADDR -#define APP_SRAM_ADDR 0x20000000 +#define APP_SRAM_ADDR 0x10000000 #endif #ifndef APP_SIZE #define APP_SIZE 0x10000 #endif - .section .text.start - .global _start -_start: - // SPI init - jal spi_init - - // Read from flash to SRAM - li a0, APP_SRAM_ADDR - li a1, APP_SIZE - li a2, APP_FLASH_ADDR - jal spi_flash_read - - // Jump to main code - li t0, APP_SRAM_ADDR - jr t0 +#define SPI_SPSR_RX_CHECK 0x01 /* Check bit 0 is cleared, fifo !empty*/ + /* Registers used + ra link register + t1 temp register + t2 temp register + s0 Image size + s1 Load address + s2 Reset vector + gp SPI master base address + a3 get_rx_data return value + t3 temp register + */ .equ SPI_BASE, 0x50000000 - .equ SPICR0, 4 * 0x08 - .equ SPICR1, 4 * 0x09 - .equ SPICR2, 4 * 0x0a - .equ SPIBR, 4 * 0x0b - .equ SPISR, 4 * 0x0c - .equ SPITXDR, 4 * 0x0d - .equ SPIRXDR, 4 * 0x0e - .equ SPICSR, 4 * 0x0f + .equ SPI_SPCR, 4 * 0x00 + .equ SPI_SPSR, 4 * 0x01 + .equ SPI_SPDR, 4 * 0x02 + .equ SPI_SPER, 4 * 0x03 + .equ SPI_SPSS, 4 * 0x04 + .section .text.start + .global _start +_start: + /* Load SPI base address to gp */ + li gp, SPI_BASE spi_init: - li a0, SPI_BASE - - li a1, 0xff - sw a1, SPICR0(a0) - - li a1, 0x80 - sw a1, SPICR1(a0) + /* Clear slave selects */ + sb zero, SPI_SPSS(gp) + + /* Set clock divider to 4 (arbitrarily chosen value) + and enable controller */ + addi t1, zero, 0x40 | 0x01 + sb t1, SPI_SPCR(gp) + + /* Set appropriate slave select */ + addi t1, zero, 1 + sb t1, SPI_SPSS(gp) + + /* Set command to READ at APP_FLASH_ADDR */ + li a0, ((APP_FLASH_ADDR & 0xFF) <<24) | ((APP_FLASH_ADDR & 0xFF00) << 8) | ((APP_FLASH_ADDR & 0xFF0000) >> 8) | 0x3 + jal spi_xfer + + /* Get magic word */ + // TODO maybe need this read for this whole thing to work correctly + // jal spi_xfer + +read_header: + // TODO do not read a header, use the compile time constant for this configuration + /* Dummy read two words */ + //jal spi_xfer + //jal spi_xfer + + /* Load image size to s0 */ + //jal spi_xfer + //jal endian_swap + li s0, APP_SIZE + + /* Load RAM base address to s1 */ + //jal spi_xfer + //jal endian_swap + li s1, APP_SRAM_ADDR + + /* Load reset vector to s2 */ + //jal spi_xfer + //jal endian_swap + li s2, APP_SRAM_ADDR + + /* Dummy read rest of header */ + //jal spi_xfer //dcrc + //jal spi_xfer //os, arch, type, comp + + //jal spi_xfer + //jal spi_xfer + //jal spi_xfer + //jal spi_xfer + //jal spi_xfer + //jal spi_xfer + //jal spi_xfer + //jal spi_xfer + + /* Clear number of copied bytes */ + addi s4, zero, 0 +copy_to_ram: + jal spi_xfer + + /* Set memory store address */ + add t1, s1, s4 + + /* Write word to RAM */ + sw a1, 0(t1) + + /* Increase counter */ + addi s4, s4, 4 + + /* Check if file is completely copied */ + bgt s0, s4, copy_to_ram + + /* Jump to entry point */ +goto_reset: + jr s2 - li a1, 0xc0 - sw a1, SPICR2(a0) + /* Reads ddccbbaa from a1, stores aabbccdd to a2 */ + /* +endian_swap: + slli a2, a1, 24 // a2 = aa000000 + srli t1, a1, 8 // t1 = 00ddccbb + andi t1, t1, 0xff // t1 = 000000bb + slli t1, t1, 16 // t1 = 00bb0000 + or a2, a2, t1 // a2 = aabb0000 - li a1, 0x03 - sw a1, SPIBR(a0) + srli t1, a1, 16 // t1 = 0000ddcc + andi t1, t1, 0xff // t1 = 000000cc + slli t1, t1, 8 // t1 = 0000cc00 + or a2, a2, t1 // a2 = aabbcc00 - li a1, 0x0f - sw a1, SPICSR(a0) + srli t1, a1, 24 // t1 = 000000dd + or a2, a2, t1 // a2 = aabbccdd ret + */ +spi_xfer: + /* Loop four times */ + addi t0, zero, 4 -// Params: -// a0 - destination pointer -// a1 - length (bytes) -// a2 - flash offset -// - -spi_flash_read: - // Save params - mv s0, a0 - mv s1, a1 - mv s2, ra - - // Setup CS - li t0, SPI_BASE - li t1, 0x0e - sw t1, SPICSR(t0) - - // Send command - li a0, 0x03 - jal _spi_do_one - - srli a0, a2, 16 - and a0, a0, 0xff - jal _spi_do_one - - srli a0, a2, 8 - and a0, a0, 0xff - jal _spi_do_one - - and a0, a2, 0xff - jal _spi_do_one - - // Read loop -_spi_loop: - li a0, 0x00 - jal _spi_do_one - sb a0, 0(s0) - addi s0, s0, 1 - addi s1, s1, -1 - bne s1, zero, _spi_loop - - // Release CS - li t0, SPI_BASE - li t1, 0x0f - sw t1, SPICSR(t0) - - // Done - jr s2 - - -// Params: a0 - Data to TX -// Returns: a0 - RX data -// Clobbers t0, t1 -_spi_do_one: - li t0, SPI_BASE - li t1, 0x08 +spi_xfer_loop: + /* Send data in a0[7:0] */ + sb a0, SPI_SPDR(gp) - // Write TX data - sw a0, SPITXDR(t0) +spi_xfer_poll: + /* Wait for data in RX FIFO */ + lbu t1, SPI_SPSR(gp) + andi t1, t1, SPI_SPSR_RX_CHECK + bnez t1, spi_xfer_poll - // Wait for RXRDY -1: - lw a0, SPISR(t0) - and a0, a0, t1 - bne a0, t1, 1b + srli a1, a1, 8 + lbu t1, SPI_SPDR(gp) + slli t1, t1, 24 + or a1, a1, t1 - // Read RX data - lw a0, SPIRXDR(t0) + srli a0, a0, 8 + addi t0, t0, -1 + bnez t0, spi_xfer_loop - // Done ret diff --git a/crush.core b/crush.core index 9bbcdc0..4ffd77f 100644 --- a/crush.core +++ b/crush.core @@ -22,6 +22,8 @@ filesets: - rtl/soc/gpio.v - rtl/soc/spi.v: {file_type: systemVerilogSource} file_type: verilogSource + depend: + - simple_spi pcf: files: @@ -99,6 +101,15 @@ filesets: - sim/top_tb.v file_type: systemVerilogSource + sim_top_freertos: + files: + - sim/top_freertos_tb.v + - sim/s25fl128s.v + - freertos/app/build/crush_freertos.data: + file_type: user + copyto: crush_freertos.data + file_type: systemVerilogSource + verilator_waiver: files: - data/verilator_waiver.vlt @@ -115,6 +126,7 @@ targets: tools: icestorm: nextpnr_options : [ "--up5k", "--package", "sg48" ] + icepack_options : [ "-s" ] yosys_synth_options: - "-dsp" icarus: @@ -122,6 +134,7 @@ targets: iverilog_options: - "-g2012" - "-gassertions" + - "-DSIM" hooks: post_run: [iceprog_hint] @@ -132,6 +145,8 @@ targets: - top_freertos - pcf toplevel: top_freertos + hooks: + post_run: [iceprog_hint_freertos] lint: default_tool : verilator @@ -228,8 +243,17 @@ targets: toplevel: top_tb default_tool: icarus + sim_top_freertos: + <<: *default + filesets_append: + - sim_top_freertos + - sim_common + - top_freertos + toplevel: top_freertos_tb + default_tool: icarus + scripts: iceprog_hint: cmd: - echo - - "Run 'iceprog ...' in the build folder to program the board" + - "Run 'iceprog -o 0x20000 freertos/app/build/crush_freertos.bin' to load firmware to flash." diff --git a/freertos/app/CMakeLists.txt b/freertos/app/CMakeLists.txt index 8f64a73..05b6f05 100644 --- a/freertos/app/CMakeLists.txt +++ b/freertos/app/CMakeLists.txt @@ -49,10 +49,13 @@ target_link_libraries(${PROJECT_NAME} PRIVATE gcc) string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) find_program(objcopy_program ${objcopy_name} REQUIRED) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${objcopy_program} -O binary -j .text -j .data -j .bss -j .stack --reverse-bytes=4 ${PROJECT_NAME} ${PROJECT_NAME}.bin + COMMAND ${objcopy_program} -O binary -j .text -j .data -j .bss -j .stack ${PROJECT_NAME} ${PROJECT_NAME}.bin WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) + +# Output is loaded to flash at offset 0x20_000. the adjust-vma makes sure it +# will be loaded into the simulation at the correct address. add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${objcopy_program} -O verilog -j .mem -j .bss -j .stack --adjust-vma -0x10000000 --verilog-data-width 4 ${PROJECT_NAME} ${PROJECT_NAME}.data + COMMAND ${objcopy_program} -O verilog --adjust-vma -0x0ffe0000 --verilog-data-width 1 ${PROJECT_NAME} ${PROJECT_NAME}.data WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/freertos/app/src/hal.c b/freertos/app/src/hal.c index 609b63c..b2269fc 100644 --- a/freertos/app/src/hal.c +++ b/freertos/app/src/hal.c @@ -4,7 +4,7 @@ void delay() { - vTaskDelay(pdMS_TO_TICKS(50)); + vTaskDelay(pdMS_TO_TICKS(1000)); } #define GPIO_BASE_ADDRESS ((int *)0x40000000) diff --git a/requirements.txt b/requirements.txt index 857a2bd..ed9f0cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.13 # by the following command: # # pip-compile @@ -84,8 +84,6 @@ ruamel-yaml==0.18.6 # via # riscv-config # riscv-isac -ruamel-yaml-clib==0.2.8 - # via ruamel-yaml simplesat==0.8.2 # via fusesoc six==1.16.0 diff --git a/rtl/cpu/mtimer.v b/rtl/cpu/mtimer.v index 86ba6c8..56c078c 100644 --- a/rtl/cpu/mtimer.v +++ b/rtl/cpu/mtimer.v @@ -50,7 +50,7 @@ module mtimer #( err_o <= 0; rty_o <= 0; - if(rst_i) begin + if(rst_i) begin : reset integer i; for(i = 0; i < 4; i++) mem[i] <= 0; interrupt <= 0; diff --git a/rtl/soc/spi.v b/rtl/soc/spi.v index 4389b1f..9d864d7 100644 --- a/rtl/soc/spi.v +++ b/rtl/soc/spi.v @@ -1,8 +1,5 @@ `default_nettype none -/* - * Interface to hard SPI unit 0. - */ module spi #( parameter integer BASE_ADDRESS ) ( @@ -27,87 +24,38 @@ module spi #( inout wire flash_mosi, output wire flash_cs_n ); - reg [31:0] data = {24'h0, spi_sbdato}; - - assign ack_o = spi_sbacko; + reg[7:0] spi_dat_o; + wire [31:0] data = {24'h0, spi_dat_o}; assign dat_o = ack_o ? data : 32'hzzzz_zzzz; wire addressed = (adr_i >= BASE_ADDRESS) & (adr_i < BASE_ADDRESS + 4 * 32'h10); + wire[31:0] address = adr_i - BASE_ADDRESS; -wire spi_sbclki = clk_i; -wire spi_sbrwi = we_i; -wire spi_sbstbi = addressed & cyc_i & stb_i; -wire [7:0] spi_sbadri = {4'b0010, adr_i[3+2:2]}; -wire [7:0] spi_sbdati = dat_i[7:0]; -wire spi_mi; -wire spi_si; -wire spi_scki; -wire spi_scsni = 1; -wire [7:0] spi_sbdato; -wire spi_sbacko; -wire spi_spiirq; -wire spi_spiwkup; -wire spi_so; -wire spi_soe; -wire spi_mo; -wire spi_moe; -wire spi_scko; -wire spi_sckoe; -wire [3:0] spi_mcsno; -wire [3:0] spi_mcsnoe; + // Interrupt output is ignored. The CPU is programmed to send commands slow + // enough that we will not overflow the FIFOs without using the interrupt. + simple_spi spi ( + // Wishbone + .clk_i (clk_i), + .rst_i (rst_i), + .adr_i (address[9-:8]), + .dat_i (dat_i[7:0]), + .we_i (we_i), + .cyc_i (addressed & cyc_i), + .stb_i (addressed & stb_i), + .dat_o (spi_dat_o), + .ack_o (ack_o), + // SPI flash chip + .sck_o (flash_clk), + .ss_o (flash_cs_n), + .mosi_o (flash_mosi), + .miso_i (flash_miso) + ); -SB_SPI #(.BUS_ADDR74("0b0010")) spi ( - .SBCLKI(spi_sbclki), - .SBRWI(spi_sbrwi), - .SBSTBI(spi_sbstbi), - .SBADRI7(spi_sbadri[7]), - .SBADRI6(spi_sbadri[6]), - .SBADRI5(spi_sbadri[5]), - .SBADRI4(spi_sbadri[4]), - .SBADRI3(spi_sbadri[3]), - .SBADRI2(spi_sbadri[2]), - .SBADRI1(spi_sbadri[1]), - .SBADRI0(spi_sbadri[0]), - .SBDATI7(spi_sbdati[7]), - .SBDATI6(spi_sbdati[6]), - .SBDATI5(spi_sbdati[5]), - .SBDATI4(spi_sbdati[4]), - .SBDATI3(spi_sbdati[3]), - .SBDATI2(spi_sbdati[2]), - .SBDATI1(spi_sbdati[1]), - .SBDATI0(spi_sbdati[0]), - .MI(spi_mi), - .SI(spi_si), - .SCKI(spi_scki), - .SCSNI(spi_scsni), - .SBDATO7(spi_sbdato[7]), - .SBDATO6(spi_sbdato[6]), - .SBDATO5(spi_sbdato[5]), - .SBDATO4(spi_sbdato[4]), - .SBDATO3(spi_sbdato[3]), - .SBDATO2(spi_sbdato[2]), - .SBDATO1(spi_sbdato[1]), - .SBDATO0(spi_sbdato[0]), - .SBACKO(spi_sbacko), - .SPIIRQ(spi_spiirq), - .SPIWKUP(spi_spiwkup), - .SO(spi_so), - .SOE(spi_soe), - .MO(spi_mo), - .MOE(spi_moe), - .SCKO(spi_scko), - .SCKOE(spi_sckoe), - .MCSNO3(spi_mcsno[3]), - .MCSNO2(spi_mcsno[2]), - .MCSNO1(spi_mcsno[1]), - .MCSNO0(spi_mcsno[0]), - .MCSNOE3(spi_mcsnoe[3]), - .MCSNOE2(spi_mcsnoe[2]), - .MCSNOE1(spi_mcsnoe[1]), - .MCSNOE0(spi_mcsnoe[0]) -); + assign err_o = 0; + assign rty_o = 0; +/* SB_IO #( .PIN_TYPE(6'b101001), .PULLUP(1'b1) @@ -117,7 +65,6 @@ SB_SPI #(.BUS_ADDR74("0b0010")) spi ( .D_OUT_0 ({spi_mo, spi_so, spi_scko }), .D_IN_0 ({spi_si, spi_mi, spi_scki }) ); - - assign flash_cs_n = spi_mcsno[0]; +*/ endmodule diff --git a/rtl/soc/top_freertos.v b/rtl/soc/top_freertos.v index 67e598a..49bf4a3 100644 --- a/rtl/soc/top_freertos.v +++ b/rtl/soc/top_freertos.v @@ -26,7 +26,9 @@ wire ack_i; wire err_i; wire rty_i; -cpu #(.INITIAL_PC('h0000_0000), .TRAP_PC('h1000_0100)) dut ( +wire timer_interrupt; + +cpu #(.INITIAL_PC('h0000_0000), .TRAP_PC('h1000_0100)) cpu ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), @@ -38,7 +40,9 @@ cpu #(.INITIAL_PC('h0000_0000), .TRAP_PC('h1000_0100)) dut ( .cyc_o(cyc_o), .adr_o(adr_o), .sel_o(sel_o), - .we_o(we_o) + .we_o(we_o), + .timer_interrupt(timer_interrupt), + .external_interrupt(1'b0) ); wire boot_rom_ack_o; @@ -83,6 +87,25 @@ wire ram_err_o; .rty_o(ram_rty_o) ); +wire mtimer_ack_o; +wire mtimer_err_o; +wire mtimer_rty_o; +mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(mtimer_ack_o), + .err_o(mtimer_err_o), + .rty_o(mtimer_rty_o), + .interrupt(timer_interrupt) +); + wire gpio_ack_o; wire gpio_rty_o; wire gpio_err_o; @@ -126,8 +149,8 @@ spi #(.BASE_ADDRESS('h5000_0000)) spi ( .flash_cs_n(FLASH_SSB) ); -assign ack_i = boot_rom_ack_o | ram_ack_o | gpio_ack_o | spi_ack_o; -assign err_i = boot_rom_err_o | ram_err_o | gpio_err_o | spi_err_o; -assign rty_i = boot_rom_rty_o | ram_rty_o | gpio_rty_o | spi_rty_o; +assign ack_i = boot_rom_ack_o | ram_ack_o | mtimer_ack_o | gpio_ack_o | spi_ack_o; +assign err_i = boot_rom_err_o | ram_err_o | mtimer_err_o | gpio_err_o | spi_err_o; +assign rty_i = boot_rom_rty_o | ram_rty_o | mtimer_rty_o | gpio_rty_o | spi_rty_o; endmodule diff --git a/script/init.sh b/script/init.sh index 55baf01..9078454 100755 --- a/script/init.sh +++ b/script/init.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash export YOSYS_DATDIR=$(yosys-config --datdir) + +rm -rf fusesoc_libraries fusesoc library add --sync-type local crush . +fusesoc library add fusesoc_cores https://github.com/fusesoc/fusesoc-cores diff --git a/sim/s25fl128s.v b/sim/s25fl128s.v new file mode 100644 index 0000000..3bb5113 --- /dev/null +++ b/sim/s25fl128s.v @@ -0,0 +1,8077 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl128s.v +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2009-2019 Free Model Foundry; http://www.FreeModelFoundry.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 V.Mancev 23 Nov 09 Initial +// R.Prokopovic +// V1.1 V.Mancev 24 Feb 10 addr_cnt for second read in +// high performance read continuous +// mode can change its value only +// when CSNeg = '0' +// V1.2 V.Mancev 23 Mar 10 During read operations read_out +// signal changes its value in +// shorter interval +// V1.3 V.Mancev 13 Apr 10 HOLD mode corrected +// Condition for PP operation +// corrected +// V1.4 V.Mancev 19 May 10 SRWD bit assignment is corrected +// Condition for WRR command in +// write_cycle _decode section is +// corrected +// Blocking assignments for signals +// WSTART and PSTART are replaced +// with nonblocking assignments +// Conditions in Page Program +// section are fixed +// V1.5 V.Mancev 26 May 10 Conditions in programming +// sections are fixed +// Timing control sections for +// Program and Erase operation are +// changed +// V1.6 V.Mancev 03 June 10 bus_cycle_state section for +// PGSP command is fixed +// V1.7 V.Mancev 29 July 10 During the QUAD mode HOLD# input +// is not monitored for its normal +// function +// V1.8 B.Colakovic 24 Aug 10 All redundant signals are removed +// from BusCycle process +// V1.9 V. Mancev 08 Oct 10 Latest datasheet aligned +// B.Colakovic +// R. Prokopovic +// V1.10 V. Mancev 01 Nov 10 Read Configuration register added +// B.Colakovic for any state. Hybrid configuration +// R. Prokopovic added +// V1.11 S.Petrovic 08 Apr 11 Corrected timing in always block +// that generates +// rising_edge_CSNeg_ipd +// V1.12 V. Mancev 11 May 11 Condition for CS# High Time +// (Program/Erase) is fixed +// V1.13 V. Mancev 01 July 11 Latest datasheet aligned +// V1.14 B.Colakovic 14 July 11 Optimization issue is fixed +// V1.15 V.Mancev 22 July 11 Timing check issue is fixed +// V1.16 V. Mancev 16 Nov 11 Time tHO is changed to 1 ns +// (customer's request) +// BRWR instruction is corrected +// V1.17 S.Petrovic 28 Aug 12 QPP Instruction is allowed on +// previously programmed page +// V1.18 S.Petrovic 30 Aug 12 Wrong code corrected +// V1.19 V. Mancev 13 Feb 13 Reverted restriction for QPP +// on programmed page and +// added clearing with sector erase +// V1.20 S.Petrovic 13 Nov 28 Corrected state transitions +// initiated by Power-Up and HW +// Reset in StateGen process +// V1.21 S.Petrovic 13 Dec 16 Corrected Read DLP. +// Corrected Autoboot reg decoding +// V1.22 M.Stojanovic 15 May 15 Ignored upper address bits for RD4 +// V1.23 M.Stojanovic 15 May 29 Ignored upper address bits for all +// commands in QUAD mode +// V1.24 M.Stojanovic 16 May 11 During QPP and QPP4 commands +// the same page must not be +// programmed more than once. However +// do not generate P_ERR if this +// occurs. +// V1.25 M.Dinic 19 Feb 12 Updated according rev *P +// B.Barac (QPP and QPP4 commands changed, +// ECCRD command added, +// LOCK bit removed) +// +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL128S +// +// Description: 128 Megabit Serial Flash Memory +// +////////////////////////////////////////////////////////////////////////////// +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// A device ordering (trim) option determines whether a feature is enabled +// or not, or provide relevant parameters: +// -15th character in TimingModel determines if enhanced high +// performance option is available +// (0,2,3,R,A,B,C,D) EHPLC +// (Y,Z,S,T,K,L) Security EHPLC +// (4,6,7,8,9,Q) HPLC +// -15th character in TimingModel determines if RESET# input +// is available +// (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +// (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +// state,inside the package. +// -16th character in TimingModel determines Sector and Page Size: +// (0) Sector Size = 64 kB; Page Size = 256 bytes +// Hybrid Top/Bottom sector size architecture +// (1) Sector Size = 256 kB; Page Size = 512 bytes +// Uniform sector size architecture +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl128s + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + RSTNeg , + WPNeg , + HOLDNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + + inout SI ; + inout SO ; + + input SCK ; + input CSNeg ; + input RSTNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire RSTNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire RSTNeg_in ; + //Internal pull-up + assign RSTNeg_in = (RSTNeg_ipd === 1'bx) ? 1'b1 : RSTNeg_ipd; + + // internal delays + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg WRR_in ; + reg WRR_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg PU_in ; + reg PU_out ; + reg RST_in ; + reg RST_out ; + reg PPBERASE_in ; + reg PPBERASE_out; + reg PASSULCK_in ; + reg PASSULCK_out; + reg PASSACC_in ; + reg PASSACC_out; + + // event control registers + reg PRGSUSP_out_event; + reg ERSSUSP_out_event; + reg Reseted_event; + reg SCK_ipd_event; + reg next_state_event; + + reg rising_edge_PoweredUp = 1'b0; + reg rising_edge_Reseted = 1'b0; + reg rising_edge_PASSULCK_in = 1'b0; + reg rising_edge_RES_out = 1'b0; + reg rising_edge_PSTART = 1'b0; + reg rising_edge_WSTART = 1'b0; + reg rising_edge_ESTART = 1'b0; + reg rising_edge_RSTNeg = 1'b0; + reg rising_edge_RST = 1'b0; + reg falling_edge_RSTNeg = 1'b0; + reg falling_edge_RST = 1'b0; + reg rising_edge_RST_out = 1'b0; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg RST ; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl128s.mem"; + parameter otp_file_name = "s25fl128sOTP.mem";//"none"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl128s"; + parameter MaxData = 255; + parameter MemSize = 24'hFFFFFF; + parameter SecSize256 = 20'h3FFFF; + parameter SecSize64 = 16'hFFFF; + parameter SecSize4 = 12'hFFF; + parameter SecNum64 = 285; + parameter SecNum256 = 63; + parameter PageNum64 = 20'h1FFFF; + parameter PageNum256 = 16'h7FFF; + parameter AddrRANGE = 24'hFFFFFF; + parameter HiAddrBit = 31; + parameter OTPSize = 1023; + parameter OTPLoAddr = 12'h000; + parameter OTPHiAddr = 12'h3FF; + parameter BYTE = 8; + + // Manufacturer Identification + parameter Manuf_ID = 8'h01; + parameter DeviceID = 8'h17; + // Electronic Signature + parameter ESignature = 8'h17; + // Device ID + //Manufacturer Identification && Memory Type && Memory Capacity + parameter Jedec_ID = 8'h01; + parameter DeviceID1 = 8'h20; + parameter DeviceID2 = 8'h18; + parameter ExtendedBytes = 8'h4D; + parameter ExtendedID64 = 8'h01; + parameter ExtendedID256 = 8'h00; + parameter DieRev = 8'h03; + parameter MaskRev = 8'h00; + + integer PageSize; + integer PageNum; + integer SecSize; + integer b_act = 0; + + integer ASP_ProtSE = 0; + integer Sec_ProtSE = 0; + + integer EHP; //Enhanced High Performance Mode active + + integer BAR_ACC = 0; //Bank Register Access active + + //varaibles to resolve architecture used + reg [24*8-1:0] tmp_timing;//stores copy of TimingModel + reg [7:0] tmp_char1;//Define EHPLC or HPLC Mode + reg [7:0] tmp_char2;//stores "0" or "1" character defining sector/page size + integer found = 1'b0; + + // If speedsimulation is needed uncomment following line + + `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // Memory Array Configuration + reg BottomBoot = 1'b0; + reg TopBoot = 1'b0; + reg UniformSec = 1'b0; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; + + reg TSU ; + + reg RES_TO_SUSP_MIN_TIME; + reg RES_TO_SUSP_TYP_TIME; + + reg WDONE ; + reg WSTART ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + reg ERS_SUSP_PG_SUSP_ACT; + + reg Reseted ; + + reg PARAM_REGION = 1'b0; + + // Lock Bit is enabled for customer programming + reg WRLOCKENABLE = 1'b1; + // Flag that mark if ASP Register is allready programmed + reg ASPOTPFLAG = 1'b0; + + //Flag for Password unlock command + reg PASS_UNLOCKED = 1'b0; + reg [63:0] PASS_TEMP = 64'hFFFFFFFFFFFFFFFF; + + reg QUADRD = 1'b0; + reg INITIAL_CONFIG = 1'b0; + reg CHECK_FREQ = 1'b0; + + // Programming buffer + integer WByte[0:511]; + // CFI array + integer CFI_array[8'h00:8'h50]; + // OTP Memory Array + integer OTPMem[OTPLoAddr:OTPHiAddr]; + // Flash Memory Array + integer Mem[0:AddrRANGE]; + + // Registers + // VDLR Register + reg[7:0] VDLR_reg = 8'h00; + reg[7:0] VDLR_reg_in = 8'h00; + // NVDLR Register + reg[7:0] NVDLR_reg = 8'h00; + reg[7:0] NVDLR_reg_in = 8'h00; + reg start_dlp = 1'b0; + + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRWD ; + wire P_ERR; + wire E_ERR; + wire [2:0]BP; + wire WEL; + wire WIP; + assign SRWD = Status_reg1[7]; + assign P_ERR = Status_reg1[6]; + assign E_ERR = Status_reg1[5]; + assign BP = Status_reg1[4:2]; + assign WEL = Status_reg1[1]; + assign WIP = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire ES ; + wire PS ; + assign ES = Status_reg2[1]; + assign PS = Status_reg2[0]; + + // Configuration Register 1 + reg[7:0] Config_reg1 = 8'h00; + reg[7:0] Config_reg1_in = 8'h00; + + wire LC1 ; + wire LC0 ; + wire TBPROT ; +// wire LOCK ; + wire BPNV ; + wire TBPARM ; + wire QUAD ; + wire FREEZE ; + assign LC1 = Config_reg1[7]; + assign LC0 = Config_reg1[6]; + assign TBPROT = Config_reg1[5]; +// assign LOCK = Config_reg1[4]; + assign BPNV = Config_reg1[3]; + assign TBPARM = Config_reg1[2]; + assign QUAD = Config_reg1[1]; + assign FREEZE = Config_reg1[0]; + + // Autoboot Register + reg[31:0] AutoBoot_reg = 32'h00000000; + reg[31:0] AutoBoot_reg_in = 32'h00000000; + + wire ABE; + assign ABE = AutoBoot_reg[0]; + + // Bank Address Register + reg [7:0] Bank_Addr_reg = 8'h00; + reg [7:0] Bank_Addr_reg_in = 8'h00; + + wire EXTADD; + assign EXTADD = Bank_Addr_reg[7]; + + // ECC Status Register + reg[7:0] ECCSR = 8'h00; + + wire EECC; + wire EECCD; + wire ECCDI; + + assign EECC = ECCSR[2]; + assign EECCD = ECCSR[1]; + assign ECCDI = ECCSR[0]; + + // ASP Register + reg[15:0] ASP_reg ; + reg[15:0] ASP_reg_in; + + wire RPME ; + wire PPBOTP ; + wire PWDMLB ; + wire PSTMLB ; + assign RPME = ASP_reg[5]; + assign PPBOTP = ASP_reg[3]; + assign PWDMLB = ASP_reg[2]; + assign PSTMLB = ASP_reg[1]; + + // Password register + reg[63:0] Password_reg = 64'hFFFFFFFFFFFFFFFF; + reg[63:0] Password_reg_in = 64'hFFFFFFFFFFFFFFFF; + + // PPB Lock Register + reg[7:0] PPBL = 8'h00; + reg[7:0] PPBL_in = 8'h00; + + wire PPB_LOCK ; + assign PPB_LOCK = PPBL[0]; + + // PPB Access Register + reg[7:0] PPBAR = 8'hFF; + reg[7:0] PPBAR_in = 8'hFF; + + reg[SecNum64:0] PPB_bits = {286{1'b1}}; + + // DYB Access Register + reg[7:0] DYBAR = 8'hFF; + reg[7:0] DYBAR_in = 8'hFF; + + reg[SecNum64:0] DYB_bits = {286{1'b1}}; + + //The Lock Protection Registers for OTP Memory space + reg[7:0] LOCK_BYTE1; + reg[7:0] LOCK_BYTE2; + reg[7:0] LOCK_BYTE3; + reg[7:0] LOCK_BYTE4; + + // Command Register + reg write; + reg cfg_write; + reg read_out; + reg dual = 1'b0; + reg rd_fast = 1'b1; + reg rd_slow = 1'b0; + reg ddr = 1'b0; + reg ddr80 = 1'b0; + reg ddr_fast = 1'b0; + reg hold_mode = 1'b0; + reg any_read = 1'b0; + reg quad_pg = 1'b0; + + wire rd ; + wire fast_rd ; + wire ddrd ; + wire fast_ddr ; + wire ddrd80 ; + + wire quadpg ; + assign quadpg = quad_pg; + + wire RD_EQU_1; + assign RD_EQU_1 = any_read; + + wire RD_EQU_0; + assign RD_EQU_0 = ~any_read; + + reg change_TBPARM = 0; + + reg change_BP = 0; + reg [2:0] BP_bits = 3'b0; + + reg DOUBLE = 1'b0; //Double Data Rate (DDR) flag + + reg RdPswdProtMode = 1'b0;//Read Password Protection Mode Active flag + reg RdPswdProtEnable = 1'b0;//Read Password Protection Mode Support flag + + integer Byte_number = 0; + + reg oe = 1'b0; + reg oe_z = 1'b0; + + reg [647:0] CFI_array_tmp ; + reg [7:0] CFI_tmp; + + integer start_delay; + reg start_autoboot; + integer ABSD; + + reg change_addr ; + integer Address = 0; + integer SectorSuspend = 0; + + //Sector and subsector addresses + integer SA = 0; + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [SecNum64:0] Sec_Prot = {286{1'b0}}; + + // timing check violation + reg Viol = 1'b0; + + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + reg[63:0] old_pass; + reg[63:0] new_pass; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer byte_cnt = 1; + integer read_addr = 0; + integer read_addr_tmp = 0; + integer Sec_addr = 0; + integer SecAddr = 0; + integer Page_addr = 0; + integer pgm_page = 0; + + reg[7:0] data_out; + reg[647:0] ident_out; + + time SCK_cycle = 0; + time prev_SCK; + time start_ddr; + time out_time; + time SCK_SO_DDR; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (RSTNeg_ipd, RSTNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + wire deh_pin; + wire deh_sout; + wire deh_ddr_sout; + wire deh_holdin; + //VHDL VITAL CheckEnable equivalents + wire quad_rd; + assign quad_rd = deg_holdin && ~QUAD && (SIOut_z != 1'bz); + wire wr_prot; + assign wr_prot = SRWD && WEL && ~QUAD; + wire dual_rd; + assign dual_rd = dual ; + wire ddro; + assign ddro = ddr && ~ddr80 && ~dual ; + wire ddro80; + assign ddro80 = ddr && ddr80 && ~dual ; + wire ddr_rd; + assign ddr_rd = PoweredUp && ddr; + wire sdr_rd; + assign sdr_rd = PoweredUp && ~ddr; +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_normal =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + specparam tpd_RSTNeg_SO =1; + //DDR operation values + specparam tpd_SCK_SO_DDR =1; + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; + specparam tsetup_SI_SCK_normal =1; + specparam tsetup_WPNeg_CSNeg =1; + specparam tsetup_HOLDNeg_SCK =1; + specparam tsetup_RSTNeg_CSNeg =1; + // DDR operation values + specparam tsetup_SI_SCK_DDR =1; + specparam tsetup_SI_SCK_DDR_fast =1; + specparam tsetup_CSNeg_SCK_DDR =1; + + //thold values: hold times + specparam thold_CSNeg_SCK =1; + specparam thold_SI_SCK_normal =1; + specparam thold_SO_SCK_normal =1; + specparam thold_WPNeg_CSNeg =1; + specparam thold_HOLDNeg_SCK =1; + specparam thold_CSNeg_RSTNeg =1; + // DDR operation values + specparam thold_SI_SCK_DDR =1; + specparam thold_SI_SCK_DDR_fast =1; + specparam thold_CSNeg_SCK_DDR =1; + + // tpw values: pulse width + specparam tpw_SCK_serial_posedge =1; + specparam tpw_SCK_dual_posedge =1; + specparam tpw_SCK_fast_posedge =1; + specparam tpw_SCK_quadpg_posedge =1; + specparam tpw_SCK_serial_negedge =1; + specparam tpw_SCK_dual_negedge =1; + specparam tpw_SCK_fast_negedge =1; + specparam tpw_SCK_quadpg_negedge =1; + specparam tpw_CSNeg_read_posedge =1; + specparam tpw_CSNeg_pgers_posedge =1; + specparam tpw_RSTNeg_negedge =1; + specparam tpw_RSTNeg_posedge =1; + // DDR operation values + specparam tpw_SCK_DDR_posedge =1; + specparam tpw_SCK_DDR_negedge =1; + specparam tpw_SCK_DDR80_posedge =1; + specparam tpw_SCK_DDR80_negedge =1; + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_serial_rd =1;// 50 MHz + specparam tperiod_SCK_fast_rd =1;//133 MHz + specparam tperiod_SCK_dual_rd =1;//104 MHz + specparam tperiod_SCK_quadpg =1;// 80 MHz + // DDR operation values + specparam tperiod_SCK_DDR_rd =1;// 66 MHz + specparam tperiod_SCK_DDR80_rd =1;// 80 MHz + + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP_256 = 75e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e7;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e7;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 165e9;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e9;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + // Data In Setup Max time + specparam tdevice_TSU = 300e3; + `else + // Page Program Operation + specparam tdevice_PP_256 = 75e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e9;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e9;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 165e12;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e11;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + // Data In Setup Max time + specparam tdevice_TSU = 300e3; + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~ddr) (SCK => SO) = tpd_SCK_SO_normal; + if (ddr || rd_fast) (SCK => SO) = tpd_SCK_SO_DDR; + + if (~ddr && dual) (SCK => SI) = tpd_SCK_SO_normal; + if ( ddr && dual) (SCK => SI) = tpd_SCK_SO_DDR; + + if (~ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_DDR; + if (~ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_DDR; + + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (CSNeg && dual) (CSNeg => SI) = tpd_CSNeg_SO; + + if (CSNeg && QUAD) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; + if (CSNeg && QUAD) (CSNeg => WPNeg) = tpd_CSNeg_SO; + + if (~QUAD) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (~QUAD && dual) (HOLDNeg => SI) = tpd_HOLDNeg_SO; + + (RSTNeg => SO) = tpd_RSTNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& sdr_rd, + tsetup_CSNeg_SCK, Viol); + $setup ( CSNeg , posedge SCK &&& ddr_rd, + tsetup_CSNeg_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK_normal, Viol); + $setup ( WPNeg , negedge CSNeg &&& wr_prot, + tsetup_WPNeg_CSNeg, Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_rd, + tsetup_HOLDNeg_SCK, Viol); + $setup ( SI , posedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& ddro80, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro80, + tsetup_SI_SCK_DDR, Viol); + + $setup ( RSTNeg , negedge CSNeg, + tsetup_RSTNeg_CSNeg, Viol); + + $hold ( posedge SCK &&& sdr_rd , CSNeg, + thold_CSNeg_SCK, Viol); + $hold ( posedge SCK &&& ddr_rd , CSNeg, + thold_CSNeg_SCK_DDR, Viol); + $hold ( posedge SCK &&& deg_sin , SI , + thold_SI_SCK_normal, Viol); + $hold ( negedge SCK &&& deh_sout , SO , + thold_SO_SCK_normal, Viol); + $hold ( negedge SCK &&& deh_ddr_sout , SO , + thold_SO_SCK_normal, Viol); + $hold ( posedge SCK &&& deh_ddr_sout , SO , + thold_SO_SCK_normal, Viol); + $hold ( posedge CSNeg &&& wr_prot , WPNeg , + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK &&& quad_rd , HOLDNeg , + thold_HOLDNeg_SCK, Viol); + $hold ( posedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( posedge SCK &&& ddro80 , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro80 , SI, + thold_SI_SCK_DDR, Viol); + + $hold ( negedge RSTNeg , CSNeg, + thold_CSNeg_RSTNeg, Viol); + + $width ( posedge SCK &&& rd , tpw_SCK_serial_posedge); + $width ( negedge SCK &&& rd , tpw_SCK_serial_negedge); + $width ( posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width ( negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width ( posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width ( posedge SCK &&& ddrd , tpw_SCK_DDR_posedge); + $width ( negedge SCK &&& ddrd , tpw_SCK_DDR_negedge); + $width ( posedge SCK &&& ddrd80 , tpw_SCK_DDR80_posedge); + $width ( negedge SCK &&& ddrd80 , tpw_SCK_DDR80_negedge); + $width ( posedge SCK &&& quadpg , tpw_SCK_quadpg_posedge); + $width ( negedge SCK &&& quadpg , tpw_SCK_quadpg_negedge); + + $width ( posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgers_posedge); + $width ( negedge RSTNeg , tpw_RSTNeg_negedge); + $width ( posedge RSTNeg , tpw_RSTNeg_posedge); + + $period ( posedge SCK &&& rd , tperiod_SCK_serial_rd); + $period ( posedge SCK &&& fast_rd , tperiod_SCK_fast_rd); + $period ( posedge SCK &&& dual_rd , tperiod_SCK_dual_rd); + $period ( posedge SCK &&& quadpg , tperiod_SCK_quadpg); + $period ( posedge SCK &&& ddrd , tperiod_SCK_DDR_rd); + $period ( posedge SCK &&& ddrd80 , tperiod_SCK_DDR80_rd); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 5'd0; + parameter RESET_STATE = 5'd1; + parameter AUTOBOOT = 5'd2; + parameter WRITE_SR = 5'd3; + parameter PAGE_PG = 5'd4; + parameter OTP_PG = 5'd5; + parameter PG_SUSP = 5'd6; + parameter SECTOR_ERS = 5'd7; + parameter BULK_ERS = 5'd8; + parameter ERS_SUSP = 5'd9; + parameter ERS_SUSP_PG = 5'd10; + parameter ERS_SUSP_PG_SUSP= 5'd11; + parameter PASS_PG = 5'd12; + parameter PASS_UNLOCK = 5'd13; + parameter PPB_PG = 5'd14; + parameter PPB_ERS = 5'd15; + parameter AUTOBOOT_PG = 5'd16; + parameter ASP_PG = 5'd17; + parameter PLB_PG = 5'd18; + parameter DYB_PG = 5'd19; + parameter NVDLR_PG = 5'd20; + + reg [4:0] current_state; + reg [4:0] next_state; + +// Instruction type + parameter NONE = 7'd0; + parameter WRR = 7'd1; + parameter PP = 7'd2; + parameter READ = 7'd3; + parameter WRDI = 7'd4; + parameter RDSR = 7'd5; + parameter WREN = 7'd6; + parameter RDSR2 = 7'd7; + parameter FSTRD = 7'd8; + parameter FSTRD4 = 7'd9; + parameter DDRFR = 7'd10; + parameter DDRFR4 = 7'd11; + parameter PP4 = 7'd12; + parameter RD4 = 7'd13; + parameter ABRD = 7'd14; + parameter ABWR = 7'd15; + parameter BRRD = 7'd16; + parameter BRWR = 7'd17; + parameter P4E = 7'd19; + parameter P4E4 = 7'd20; + parameter ASPRD = 7'd21; + parameter ASPP = 7'd22; + parameter CLSR = 7'd23; + parameter QPP = 7'd24; + parameter QPP4 = 7'd25; + parameter RDCR = 7'd26; + parameter DOR = 7'd27; + parameter DOR4 = 7'd28; + parameter DLPRD = 7'd29; + parameter OTPP = 7'd30; + parameter PNVDLR = 7'd31; + parameter OTPR = 7'd32; + parameter WVDLR = 7'd33; + parameter BE = 7'd34; + parameter QOR = 7'd35; + parameter QOR4 = 7'd36; + parameter ERSP = 7'd37; + parameter ERRS = 7'd38; + parameter PGSP = 7'd39; + parameter PGRS = 7'd40; + parameter REMS = 7'd41; + parameter RDID = 7'd42; + parameter MPM = 7'd43; + parameter PLBWR = 7'd44; + parameter PLBRD = 7'd45; + parameter RES = 7'd46; + parameter DIOR = 7'd47; + parameter DIOR4 = 7'd48; + parameter DDRDIOR = 7'd49; + parameter DDRDIOR4 = 7'd50; + parameter SE = 7'd51; + parameter SE4 = 7'd52; + parameter DYBRD = 7'd53; + parameter DYBWR = 7'd54; + parameter PPBRD = 7'd55; + parameter PPBP = 7'd56; + parameter PPBERS = 7'd57; + parameter PASSRD = 7'd58; + parameter PASSP = 7'd59; + parameter PASSU = 7'd60; + parameter QIOR = 7'd61; + parameter QIOR4 = 7'd62; + parameter DDRQIOR = 7'd63; + parameter DDRQIOR4 = 7'd64; + parameter RESET = 7'd65; + parameter MBR = 7'd66; + parameter BRAC = 7'd67; + parameter ECCRD = 7'd68; + + reg [6:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SO_in, SO_z) + begin + if (SO_in==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_pin = deq_pin; + assign deh_pin = (deq_pin == 1'b0) && (SO_z != 1'bz); + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_sin=deq_sin + && (ddr == 1'b0) && (Instruct !== DDRFR) + && (Instruct !== DDRFR4) && (Instruct !== DDRDIOR) + && (Instruct !== DDRDIOR4) && (Instruct !== DDRQIOR) + && (Instruct !== DDRQIOR4) && (SIOut_z != 1'bz); + reg deq_sout; + always @(SO_out, SIOut_z) + begin + if (SO_out==SIOut_z) + deq_sout=1'b0; + else + deq_sout=1'b1; + end + // check when data is generated from model + assign deh_sout= (deq_sout == 1'b0) + && (ddr == 1'b0) && (SOut_z != 1'bz); + assign deh_ddr_sout= (deq_sout == 1'b0) + && (ddr == 1'b1) && (SOut_z != 1'bz); + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + assign deh_holdin=(deq_holdin == 1'b0) && (HOLDNegOut_zd != 1'bz); + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + initial + begin : Init + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + cnt = 0; + RST = 1'b0; + RST_in = 1'b0; + RST_out = 1'b1; + PDONE = 1'b1; + PSTART = 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + PRGSUSP_in = 1'b0; + ERSSUSP_in = 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + Reseted = 1'b0; + + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = RESET_STATE; + next_state = RESET_STATE; + end + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl128s.mem, memory preload file + // @aaaaaa - stands for address + // dd -

is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl128s_otp memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at OTPMem(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + + LOCK_BYTE1[7:0] = OTPMem[16]; + LOCK_BYTE2[7:0] = OTPMem[17]; + LOCK_BYTE3[7:0] = OTPMem[18]; + LOCK_BYTE4[7:0] = OTPMem[19]; + end + + // initialize memory and load preload files if any + initial + begin: InitTimingModel + integer i; + integer j; + //UNIFORM OR HYBRID arch model is used + //assumptions: + //1. TimingModel has format as S25FL128SXXXXXXXX_X_XXpF + //it is important that 16-th character from first one is "0" or "1" + //2. TimingModel does not have more then 24 characters + tmp_timing = TimingModel;//copy of TimingModel + + i = 23; + while ((i >= 0) && (found != 1'b1))//search for first non null character + begin //i keeps position of first non null character + j = 7; + while ((j >= 0) && (found != 1'b1)) + begin + if (tmp_timing[i*8+j] != 1'd0) + found = 1'b1; + else + j = j-1; + end + i = i - 1; + end + i = i +1; + if (found)//if non null character is found + begin + for (j=0;j<=7;j=j+1) + begin + //EHPLC/HPLC character is 15 + tmp_char1[j] = TimingModel[(i-14)*8+j]; + //256B/512B Page character is 16 + tmp_char2[j] = TimingModel[(i-15)*8+j]; + end + end + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "Y" || + tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L") + begin + EHP = 1; + if(tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L" || tmp_char1 == "Y") + begin + RdPswdProtEnable = 1; + end + end + else if (tmp_char1 == "4" || tmp_char1 == "6" || tmp_char1 == "7" || + tmp_char1 == "8" || tmp_char1 == "9" || tmp_char1 == "Q") + begin + EHP = 0; + end + + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "4" || + tmp_char1 == "6" || tmp_char1 == "7" || tmp_char1 == "8" || + tmp_char1 == "9" || tmp_char1 == "Q") + begin + ASP_reg = 16'hFE7F; + ASP_reg_in = 16'hFE7F; + end + else if (tmp_char1 == "Y" || tmp_char1 == "Z" || tmp_char1 == "S" || + tmp_char1 == "T" || tmp_char1 == "K" || tmp_char1 == "L") + begin + ASP_reg = 16'hFE4F; + ASP_reg_in = 16'hFE4F; + end + + if (tmp_char2 == "0") + begin + PageSize = 255; + PageNum = PageNum64; + SecSize = SecSize64; + end + else if (tmp_char2 == "1") + begin + PageSize = 511; + PageNum = PageNum256; + SecSize = SecSize256; + end + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + /////////////////////////////////////////////////////////////////////// + // ID-CFI array data + /////////////////////////////////////////////////////////////////////// + // Manufacturer and Device ID + CFI_array[8'h00] = Jedec_ID; + CFI_array[8'h01] = DeviceID1; + CFI_array[8'h02] = DeviceID2; + CFI_array[8'h03] = 8'h00; + if (tmp_char2 == "0") + // Uniform 64kB sectors + CFI_array[8'h04] = ExtendedID64; + else if (tmp_char2 == "1") + // Uniform 256kB sectors + CFI_array[8'h04] = ExtendedID256; + CFI_array[8'h05] = 8'h80; + CFI_array[8'h06] = 8'h00; + CFI_array[8'h07] = 8'h00; + CFI_array[8'h08] = 8'h00; + CFI_array[8'h09] = 8'h00; + CFI_array[8'h0A] = 8'h00; + CFI_array[8'h0B] = 8'h00; + CFI_array[8'h0C] = 8'h00; + CFI_array[8'h0D] = 8'h00; + CFI_array[8'h0E] = 8'h00; + CFI_array[8'h0F] = 8'h00; + // CFI Query Identification String + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h53; + CFI_array[8'h18] = 8'h46; + CFI_array[8'h19] = 8'h51; + CFI_array[8'h1A] = 8'h00; + //CFI system interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h06; + if (tmp_char2 == "0") + begin + // 64kB sector and 256B page + CFI_array[8'h20] = 8'h08; + CFI_array[8'h21] = 8'h08; + end + else if (tmp_char2 == "1") + begin + // 256kB sector and 512B page + CFI_array[8'h20] = 8'h09; + CFI_array[8'h21] = 8'h09; + end + CFI_array[8'h22] = 8'h0F; + CFI_array[8'h23] = 8'h02; + CFI_array[8'h24] = 8'h02; + CFI_array[8'h25] = 8'h03; + CFI_array[8'h26] = 8'h03; + // Device Geometry Definition(Uniform Sector Devices) + CFI_array[8'h27] = 8'h18; + CFI_array[8'h28] = 8'h02; + CFI_array[8'h29] = 8'h01; + + if (tmp_char2 == "0") + // 64kB sectors + CFI_array[8'h2A] = 8'h08; + else if (tmp_char2 == "1") + CFI_array[8'h2A] = 8'h09; + + CFI_array[8'h2B] = 8'h00; + if (tmp_char2 == "1") + begin + CFI_array[8'h2C] = 8'h01; + CFI_array[8'h2D] = 8'h3F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h04; + CFI_array[8'h31] = 8'hFF; + CFI_array[8'h32] = 8'hFF; + CFI_array[8'h33] = 8'hFF; + CFI_array[8'h34] = 8'hFF; + end + else + begin + CFI_array[8'h2C] = 8'h02; + if (TBPARM) + begin + // 4KB physical sectors at top + CFI_array[8'h2D] = 8'hFD; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h01; + CFI_array[8'h31] = 8'h1F; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h10; + CFI_array[8'h34] = 8'h00; + end + else + begin + // 4KB physical sectors at bottom + CFI_array[8'h2D] = 8'h1F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h10; + CFI_array[8'h30] = 8'h00; + CFI_array[8'h31] = 8'hFD; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h00; + CFI_array[8'h34] = 8'h01; + end + end + CFI_array[8'h35] = 8'hFF; + CFI_array[8'h36] = 8'hFF; + CFI_array[8'h37] = 8'hFF; + CFI_array[8'h38] = 8'hFF; + CFI_array[8'h39] = 8'hFF; + CFI_array[8'h3A] = 8'hFF; + CFI_array[8'h3B] = 8'hFF; + CFI_array[8'h3C] = 8'hFF; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + // CFI Primary Vendor-Specific Extended Query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h21; + CFI_array[8'h46] = 8'h02; + CFI_array[8'h47] = 8'h01; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h08; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h00; + CFI_array[8'h4D] = 8'h00; + CFI_array[8'h4E] = 8'h00; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h01; + + begin + for(i=80;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h00-i+80]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + + end + + always @(next_state_event or PoweredUp or RST or RST_out or + RSTNeg_in or rising_edge_RSTNeg or falling_edge_RST) + begin: StateTransition + if (PoweredUp) + begin + if ((RSTNeg_in == 1'b1) && (RST_out == 1'b1)) + current_state = #(1000) next_state; + else if ((~RSTNeg_in || rising_edge_RSTNeg) && falling_edge_RST) + begin + // no state transition while RESET# low + current_state = RESET_STATE; + RST_in = 1'b1; + #1000 RST_in = 1'b0; + end + end + end + + always @(posedge RST_in) + begin:Threset + RST_out = 1'b0; + #(35000000-200000) RST_out = 1'b1; + end + + always @(negedge CSNeg_ipd) + begin:CheckCEOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_PRGSUSP PRGSUSP_out = 1'b1; + end + + always @(posedge PPBERASE_in) + begin:PPBErs + PPBERASE_out = 1'b0; + #tdevice_PPBERASE PPBERASE_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_ERSSUSP ERSSUSP_out = 1'b1; + end + + always @(posedge PASSULCK_in) + begin:PASSULock + PASSULCK_out = 1'b0; + #tdevice_PASSULCK PASSULCK_out = 1'b1; + end + + always @(posedge PASSACC_in) + begin:PASSAcc + PASSACC_out = 1'b0; + #tdevice_PASSACC PASSACC_out = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [7:0] opcode_in; + reg [7:0] opcode_tmp; + reg [31:0] addr_bytes; + reg [31:0] hiaddr_bytes; + reg [31:0] Address_in; + reg [7:0] mode_bytes; + reg [7:0] mode_in; + integer Latency_code; + integer quad_data_in [0:1023]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd or + current_state) + begin: Buscycle + integer i; + integer j; + integer k; + time CLK_PER; + time LAST_CLK; + + if (current_state == RESET_STATE) + bus_cycle_state = STAND_BY; + else + begin + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + Instruct = NONE; + write = 1'b1; + cfg_write = 0; + opcode_cnt = 0; + addr_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + data_cnt = 0; + opcode_tmp = 0; + start_dlp = 0; + DOUBLE = 1'b0; + QUADRD = 1'b0; + CLK_PER = 1'b0; + LAST_CLK = 1'b0; + if (current_state == AUTOBOOT) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = OPCODE_BYTE; + end + end + end + + if (rising_edge_SCK_ipd) // Instructions, addresses or data present + begin // at SI are latched on the rising edge of SCK + + CLK_PER = $time - LAST_CLK; + LAST_CLK = $time; + if (CHECK_FREQ) + begin + if ((CLK_PER < 20000 && Latency_code == 3) || + (CLK_PER < 12500 && Latency_code == 0) || + (CLK_PER < 11100 && Latency_code == 1) || + (CLK_PER < 9600 && Latency_code == 2)) + begin + $display ("More wait states are required for"); + $display ("this clock frequency value"); + end + if (Instruct == DDRFR || Instruct == DDRFR4 || Instruct == DDRDIOR || + Instruct == DDRDIOR4 || Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + if (CLK_PER < 12500) + begin + ddr80 = 1'b1; + end + else + begin + ddr80 = 1'b0; + end + end + CHECK_FREQ = 0; + end + + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + Latency_code = Config_reg1[7:6]; + if (opcode_cnt == BYTE) + begin + for(i=7;i>=0;i=i-1) + begin + opcode[i] = opcode_in[7-i]; + end + case (opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010011 : // 13h + begin + Instruct = RD4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : // 4Bh + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000111 : // 07h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 35h + begin + Instruct = RDCR; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : // 90h + begin + Instruct = REMS; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : // 9Fh + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011 : // ABh + begin + Instruct = RES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FSTRD; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001100 : // 0Ch + begin + Instruct = FSTRD4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001101 : // 0Dh + begin + Instruct = DDRFR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001110 : // 0Eh + begin + Instruct = DDRFR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111011 : // 3Bh + begin + Instruct = DOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111100 : // 3Ch + begin + Instruct = DOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111011 : // BBh + begin + Instruct = DIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111100 : // BCh + begin + Instruct = DIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111101 : // BDh + begin + Instruct = DDRDIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111110 : // BEh + begin + Instruct = DDRDIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101011 : // 6Bh + begin + Instruct = QOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101100 : // 6Ch + begin + Instruct = QOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101011 : // EBh + begin + Instruct = QIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101100 : // ECh + begin + Instruct = QIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101101 : // EDh + begin + Instruct = DDRQIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101110 : // EEh + begin + Instruct = DDRQIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010010 : // 12h + begin + Instruct = PP4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010: // 32h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00111000: // 38h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00110100 : // 34h + begin + Instruct = QPP4; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b01000010 : // 42h + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10000101 : // 85h + begin + Instruct = PGSP; + bus_cycle_state = DATA_BYTES; + end + 8'b10001010 : // 8Ah + begin + Instruct = PGRS; + bus_cycle_state = DATA_BYTES; + end + 8'b11000111 : // C7h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b01100000 : // 60h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011100 : // DCh + begin + Instruct = SE4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERRS; + bus_cycle_state = DATA_BYTES; + end + 8'b00010100 : // 14h + begin + Instruct = ABRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010101 : // 15h + begin + Instruct = ABWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00010110 : // 16h + begin + Instruct = BRRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010111 : // 17h + begin + Instruct = BRWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00101011 : // 2Bh + begin + Instruct = ASPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00101111 : // 2Fh + begin + Instruct = ASPP; + bus_cycle_state = DATA_BYTES; + end + 8'b11100000 : // E0h + begin + Instruct = DYBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100001 : // E1h + begin + Instruct = DYBWR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100010 : // E2h + begin + Instruct = PPBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100011 : // E3h + begin + Instruct = PPBP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100100 : // E4h + begin + Instruct = PPBERS; + bus_cycle_state = DATA_BYTES; + end + 8'b10100110 : // A6h + begin + Instruct = PLBWR; + bus_cycle_state = DATA_BYTES; + end + 8'b10100111 : // A7h + begin + Instruct = PLBRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11100111 : // E7h + begin + Instruct = PASSRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11101000 : // E8h + begin + Instruct = PASSP; + bus_cycle_state = DATA_BYTES; + end + 8'b11101001 : // E9h + begin + Instruct = PASSU; + bus_cycle_state = DATA_BYTES; + end + 8'b11110000 : // F0h + begin + Instruct = RESET; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : // 30h + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00100000 : // 20h + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00100001 : // 21h + begin + Instruct = P4E4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000001 : // 41h + begin + Instruct = DLPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b01000011 : // 43h + begin + Instruct = PNVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b01001010 : // 4Ah + begin + Instruct = WVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = BRAC; + bus_cycle_state = DATA_BYTES; + end + 8'b11111111 : // FFh + begin + Instruct = MBR; + bus_cycle_state = MODE_BYTE; + end + 8'b00011000 : // 18h + begin + Instruct = ECCRD; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + end //end of OPCODE BYTE + + ADDRESS_BYTES : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4) || + (Instruct == DDRDIOR) || (Instruct == DDRDIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + DOUBLE = 1'b1; + else + DOUBLE = 1'b0; + if ((Instruct == QOR) || (Instruct == QOR4) || + (Instruct == QIOR) || (Instruct == QIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + QUADRD = 1'b1; + else + QUADRD = 1'b0; + if (DOUBLE == 1'b0) + begin + if (((((Instruct == FSTRD) && (~EXTADD)) || + ((Instruct == DOR) && (~EXTADD)) || + (Instruct == OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QOR) && QUAD && (~EXTADD))) + begin + //Instruction + 3 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes ; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Instruct==FSTRD || Instruct==DOR || + Instruct == QOR) + begin + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct==ECCRD) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {hiaddr_bytes[31:4],4'b0000}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((((Instruct==FSTRD4) || + (Instruct==DOR4) || + ((Instruct==FSTRD) && EXTADD) || + ((Instruct==DOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct==QOR4) && QUAD) || + ((Instruct==QOR) && QUAD && EXTADD)) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {8'b00000000,hiaddr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + begin + bus_cycle_state = DUMMY_BYTES; + end + end + end + else if ((Instruct==DIOR) && (~EXTADD) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + //DUAL I/O High Performance Read(3 Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i]=Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==DIOR4) || + ((Instruct==DIOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin //DUAL I/O High Performance Read(4Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == QIOR) && (~EXTADD)) + begin + //QUAD I/O High Performance Read (3Bytes Address) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((Instruct==QIOR4) || ((Instruct==QIOR) + && EXTADD)) + begin + //QUAD I/O High Performance Read (4Bytes Addr) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt +1; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt =0; + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {8'b00000000,hiaddr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((((Instruct==RD4) || (Instruct==PP4) || + (Instruct==SE4) ||(Instruct==PPBRD) || + (Instruct==DYBRD) ||(Instruct==DYBWR) || + (Instruct==PPBP) || (Instruct==P4E4) || + ((Instruct==READ) && EXTADD) || + ((Instruct==PP) && EXTADD) || + ((Instruct==P4E) && EXTADD) || + ((Instruct==SE) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (QUAD && (Instruct==QPP4 || + ((Instruct==QPP) && EXTADD)))) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {8'b00000000,hiaddr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + else if (((HOLDNeg_in && ~QUAD) || QUAD) && + (~EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + else + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + end + end + + MODE_BYTE : + begin + if (((Instruct==DIOR) || (Instruct == DIOR4)) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + if (Latency_code == 0 || Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + mode_in[2*mode_cnt] = SI_in; + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt] = SO_in; + mode_in[4*mode_cnt+1] = SI_in; + end + else if (((Instruct==DDRQIOR) || (Instruct == DDRQIOR4)) + && QUAD) + begin + mode_in[0] = HOLDNeg_in; + mode_in[1] = WPNeg_in; + mode_in[2] = SO_in; + mode_in[3] = SI_in; + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + if ((((Instruct==FSTRD) || (Instruct==FSTRD4) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (((Instruct==QOR)||(Instruct==QOR4)) && QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + begin + bus_cycle_state = DATA_BYTES; + end + end + + else if ((Instruct==DDRFR) || (Instruct==DDRFR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==2)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==5)) || + ((Latency_code == 1) && (dummy_cnt==6)) || + ((Latency_code == 2) && (dummy_cnt==7))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (Instruct==RES) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct==ECCRD) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + bus_cycle_state = DATA_BYTES; + end + else if ((Instruct == DIOR) || (Instruct == DIOR4) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 1) && (dummy_cnt==1)) || + ((Latency_code == 2) && (dummy_cnt==2))) + bus_cycle_state = DATA_BYTES; + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + bus_cycle_state = DATA_BYTES; + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==2)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (((Instruct == QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else if (((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + + if (((Latency_code == 3) && (dummy_cnt==3)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + + DATA_BYTES : + begin + + if (DOUBLE == 1'b1 && (hold_mode==0)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + + if ((QUAD) && ((Instruct==QPP) || (Instruct == QPP4))) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SO_in, SI_in}; + if (data_cnt > ((PageSize+1)*2-1)) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for(i=0;i<=(PageSize*2-1);i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[(PageSize+1)*2-1] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + else if ((~QUADRD) && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (data_cnt > ((PageSize+1)*8-1)) + begin + //In case of serial mode and PP, + //if more than PageSize are sent to the device + //previously latched data are discarded and last + //256/512 data bytes are guaranteed to be programmed + //correctly within the same page. + if (bit_cnt == 0) + begin + for(i=0;i<=(PageSize*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[PageSize*BYTE + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + + if (falling_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + ADDRESS_BYTES : + begin + if (DOUBLE == 1'b1) + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + end + + MODE_BYTE : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + begin + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + begin + mode_in[4] = HOLDNeg_in; + mode_in[5] = WPNeg_in; + mode_in[6] = SO_in; + mode_in[7] = SI_in; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + DATA_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 ) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + else + begin + if ((Instruct==READ) || (Instruct==RD4) || + (Instruct==FSTRD)|| (Instruct==FSTRD4)|| + (Instruct==RDSR) || (Instruct==RDSR2) || + (Instruct==RDCR) || (Instruct==OTPR) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==DIOR)|| (Instruct==DIOR4)|| + (Instruct==ABRD) || (Instruct==BRRD) || + (Instruct==ASPRD)|| (Instruct==DYBRD) || + (Instruct==PPBRD)|| (Instruct == ECCRD) || + (Instruct==PASSRD)|| (Instruct==RDID)|| + (Instruct==RES) || (Instruct==REMS) || + (Instruct==PLBRD)|| (Instruct==DLPRD) || + (current_state == AUTOBOOT && + start_delay == 0) || + (((Instruct==QOR) || (Instruct==QIOR) || + (Instruct==QOR4) || + (Instruct==QIOR4)) && QUAD)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + + DUMMY_BYTES: + begin + if (hold_mode==0) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + + if (DOUBLE == 1'b1 && VDLR_reg != 8'b00000000 && + start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + endcase + end + end + + if (rising_edge_CSNeg_ipd) + begin + if (bus_cycle_state != DATA_BYTES) + begin + if (bus_cycle_state == ADDRESS_BYTES && opcode_tmp == 8'hFF) + begin + Instruct = MBR; + end + bus_cycle_state = STAND_BY; + end + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (((mode_bytes[7:4] == 4'b1010) && + (Instruct==DIOR || Instruct==DIOR4 || + Instruct==QIOR || Instruct==QIOR4)) || + ((mode_bytes[7:4] == ~mode_bytes[3:0]) && + (Instruct == DDRFR || Instruct == DDRFR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4))) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + + case (Instruct) + WREN, + WRDI, + BE, + SE, + SE4, + P4E, + P4E4, + CLSR, + BRAC, + RESET, + PPBERS, + PPBP, + PLBWR, + PGSP, + PGRS, + ERSP, + ERRS: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 0) + write = 1'b0; + end + end + + WRR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Config_reg1_in[i]= + Data_in[15-i]; + end + end + end + end + + PP, + PP4, + OTPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=7;j>=0;j=j-1) + begin + if ((Data_in[(i*8)+(7-j)]) + !== 1'bX) + begin + Byte_slv[j] = + Data_in[(i*8)+(7-j)]; + end + end + WByte[i] = Byte_slv; + end + + if (data_cnt > (PageSize+1)*BYTE) + Byte_number = PageSize; + else + Byte_number = + ((data_cnt/8) - 1); + end + end + end + end + + QPP, + QPP4: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + quad_pg = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > (PageSize+1)*2) + Byte_number = PageSize; + else + Byte_number = ((data_cnt/2)-1); + end + end + end + + ABWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 32) + begin + write = 1'b0; + for(j=0;j<=31;j=j+1) + begin + AutoBoot_reg_in[j] = Data_in[31-j]; + end + end + end + end + + BRWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + Bank_Addr_reg_in[j] = Data_in[7-j]; + end + end + end + end + + ASPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 16) + begin + write = 1'b0; + for(j=0;j<=15;j=j+1) + begin + ASP_reg_in[j] = Data_in[15-j]; + end + end + end + end + + DYBWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + DYBAR_in[j] = Data_in[7-j]; + end + end + end + end + + PNVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + NVDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + WVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + VDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + PASSP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + Password_reg_in[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + + PASSU: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + PASS_TEMP[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + endcase + end + end + end + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Page Program +/////////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed_pgm; + time elapsed_tsu; + time start_pgm; + time start_tsu; + time duration_pgm; + time duration_tsu; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == PP4) || (Instruct == OTPP) || + (Instruct == QPP) || (Instruct == QPP4)) + if (PageSize == 255) + begin + pob = tdevice_PP_256; + end + else + begin + pob = tdevice_PP_512; + end + else + pob = tdevice_BP; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed_pgm = 0; + duration_pgm = pob; + PDONE = 1'b0; + ->pdone_event; + start_pgm = $time; + end + end + + always @(posedge PGSUSP) + begin + if (PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed_pgm = $time - start_pgm; + duration_pgm = pob - elapsed_pgm; + PDONE = 1'b0; + end + end + + always @(posedge PGRES) + begin + start_pgm = $time; + ->pdone_event; + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #duration_pgm PDONE = 1'b1; + end + + always @(SI) + begin + if ((Instruct == PGSP) || (Instruct == PGRS) || + (Instruct == ERSP) || (Instruct == ERRS)) + begin + start_tsu = $time; + end + end + + always @(posedge SCK) + begin + if ((Instruct == PGSP) || (Instruct == PGRS) || + (Instruct == ERSP) || (Instruct == ERRS)) + begin + elapsed_tsu = $time - start_tsu; + duration_tsu = tdevice_TSU - elapsed_tsu; + if (duration_tsu > 0) + begin + TSU = 1'b0; + end + else + begin + TSU = 1'b1; + $display("Warning at", $time); + $display("tSU max time violation"); + end + end + end +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Write Status Register +/////////////////////////////////////////////////////////////////////////////// + time wob; + always @(posedge WSTART) + begin:wdone_process + wob = tdevice_WRR; + if (WSTART && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Reset Timing +/////////////////////////////////////////////////////////////////////////////// + + time startlo; + time starthi; + time durationlo; + time durationhi; + + always @(negedge RSTNeg_in or Instruct) + begin + if (~RSTNeg_in) + begin + RST = 1'b1; + #200000 RST = 1'b0; // 200 ns + end + else if (Instruct == RESET) + begin + Reseted = 1'b0; + #10000 Reseted = 1'b1; // 10 ns + end + end + + always @(RST_in or rising_edge_Reseted) // Reset done,program terminated + begin + if ((RST_in && ~RST) || (rising_edge_Reseted)) + disable pdone_process; + disable edone_process; + disable wdone_process; + PDONE = 1'b1; + EDONE = 1'b1; + WDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Bulk Erase +/////////////////////////////////////////////////////////////////////////////// + time seo; + time beo; + event edone_event; + time elapsed_ers; + time start_ers; + time duration_ers; + + always @(rising_edge_ESTART) + begin + if (UniformSec) + begin + seo = tdevice_SE256; + end + else + begin + seo = tdevice_SE64; + end + beo = tdevice_BE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == BE) + begin + duration_ers = beo; + end + else + begin + duration_ers = seo; + end + elapsed_ers = 0; + EDONE = 1'b0; + ->edone_event; + start_ers = $time; + end + end + + always @(posedge ESUSP) + begin + if (ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed_ers = $time - start_ers; + duration_ers = seo - elapsed_ers; + EDONE = 1'b0; + end + end + + always @(posedge ERES) + begin + if (ERES && (~EDONE)) + begin + start_ers = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_ers EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////// + // Process for clock frequency determination + /////////////////////////////////////////////////////////////////// + always @(posedge SCK_ipd) + begin : clock_period + if (SCK_ipd) + begin + SCK_cycle = $time - prev_SCK; + prev_SCK = $time; + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg falling_edge_PPBERASE_in = 1'b0; + reg falling_edge_PASSULCK_in = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or + falling_edge_RSTNeg or rising_edge_PDONE or rising_edge_WDONE or + rising_edge_EDONE or ERSSUSP_out_event or rising_edge_RSTNeg or + PRGSUSP_out_event or rising_edge_CSNeg_ipd or rising_edge_RST_out + or falling_edge_PPBERASE_in or falling_edge_PASSULCK_in or RST_out) + begin: StateGen1 + + integer sect; + + if (rising_edge_PoweredUp && RSTNeg_in && RST_out) + begin + if (ABE == 1 && RPME !== 0 ) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + else if (PoweredUp) + begin + if (RST_out == 1'b0) + next_state = current_state; + else if (falling_edge_write && Instruct == RESET) + begin + if (ABE == 1 && RPME !== 0) + begin + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + ABSD = AutoBoot_reg[8:1]; + start_autoboot = 0; + next_state = AUTOBOOT; + end + else + next_state = IDLE; + end + else + begin + case (current_state) + RESET_STATE : + begin + if ((rising_edge_RST_out && RSTNeg_in) || + (rising_edge_RSTNeg && RST_out)) + begin + if (ABE == 1 && RPME!== 0) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9],9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + end + + IDLE : + begin + if (falling_edge_write && RdPswdProtMode == 0) + begin + if (Instruct == WRR && WEL == 1 && BAR_ACC == 0 + && (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD)) + // can not execute if HPM is entered or + // if WEL bit is zero + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + $display ("WARNING: Changing value of "); + $display ("Configuration Register OTP "); + $display ("bit from 1 to 0 is not"); + $display ("allowed!!!"); + end + else + begin + next_state = WRITE_SR; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = PAGE_PG; + end + end + else if (Instruct==OTPP && WEL==1 && FREEZE==0) + begin + if (((((Address>=16'h0010 && Address<=16'h0013) + ||(Address>=16'h0020 && Address<=16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address>=16'h0100 && Address<=16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32]==1) || + ((Address>=16'h0200 && Address<=16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32]==1) || + ((Address>=16'h0300 && Address<=16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) + && (Address + Byte_number <= OTPHiAddr)) + next_state = OTP_PG; + end + else if ((Instruct == SE || Instruct == SE4) + && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 + && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + else if ((TopBoot && sect >= 254) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a + //64 KB range that includes 4 KB sectors. + next_state = SECTOR_ERS; + end + end + else if ((Instruct == P4E || Instruct == P4E4) + && WEL == 1) + begin + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + $display("The instruction is applied to"); + $display("a sector that is larger than"); + $display("4 KB."); + $display("Instruction is ignored!!!"); + end + else + begin + if (Sec_Prot[sect]== 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + end + else if (Instruct == BE && WEL == 1 && + (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0)) + next_state = BULK_ERS; + else if (Instruct == ABWR && WEL == 1) + //Autoboot Register Write Command + next_state = AUTOBOOT_PG; + else if (Instruct == BRWR) + //Bank Register Write Command + next_state = IDLE; + else if (Instruct == ASPP && WEL == 1) + begin + //ASP Register Program Command + if (~(ASPOTPFLAG)) + next_state = ASP_PG; + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + next_state = PLB_PG; + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + next_state = PASS_PG; + end + else if (Instruct == PASSU && WEL && ~WIP) + next_state = PASS_UNLOCK; + else if (Instruct == PPBP && WEL == 1) + next_state <= PPB_PG; + else if (Instruct == PPBERS && WEL && PPBOTP) + next_state <= PPB_ERS; + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == PNVDLR && WEL == 1) + next_state = NVDLR_PG; + else + next_state = IDLE; + end + if (falling_edge_write && RdPswdProtMode == 1 && ~WIP) + begin + if (Instruct == PASSU) + next_state = PASS_UNLOCK; + end + end + + AUTOBOOT : + begin + if (rising_edge_CSNeg_ipd) + next_state = IDLE; + end + + WRITE_SR : + begin + if (rising_edge_WDONE) + next_state = IDLE; + end + + PAGE_PG : + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end + + PG_SUSP : + begin + if (falling_edge_write) + begin + if (Instruct == BRWR) + //Bank Register Write Command + next_state = PG_SUSP; + else if (Instruct == PGRS) + next_state = PAGE_PG; + end + end + + OTP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + BULK_ERS : + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS : + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP : + begin + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && SectorSuspend != + Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = ERS_SUSP_PG; + end + end + end + else if (Instruct == BRWR) + begin + //Bank Register Write Command + next_state = ERS_SUSP; + end + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == ERRS) + next_state = SECTOR_ERS; + end + end + + ERS_SUSP_PG : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = ERS_SUSP_PG_SUSP; + end + + ERS_SUSP_PG_SUSP : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + next_state = ERS_SUSP_PG_SUSP; + end + else if (Instruct == PGRS) + begin + next_state = ERS_SUSP_PG; + end + end + end + + PASS_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PASS_UNLOCK : + begin + if (falling_edge_PASSULCK_in) + next_state = IDLE; + end + + PPB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PPB_ERS : + begin + if (falling_edge_PPBERASE_in) + next_state = IDLE; + end + + AUTOBOOT_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PLB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + DYB_PG : + begin + if (rising_edge_PDONE) + if (ES) + next_state = ERS_SUSP; + else + next_state = IDLE; + end + + ASP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + NVDLR_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + endcase + end + end + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer WData [0:511]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(Instruct_event) + begin + read_cnt = 0; + byte_cnt = 1; + rd_fast = 1'b1; + dual = 1'b0; + rd_slow = 1'b0; + any_read = 1'b0; + end + + always @(rising_edge_read_out) + begin + if (rising_edge_read_out == 1'b1) + begin + if (PoweredUp == 1'b1) + begin + oe_z = 1'b1; + #1000 oe_z = 1'b0; + oe = 1'b1; + #1000 oe = 1'b0; + end + end + end + + always @(change_addr_event) + begin + if (change_addr_event) + begin + read_addr = Address; + end + end + + always @(posedge PASSACC_out) + begin + Status_reg1[0] = 1'b0; //WIP + PASSACC_in = 1'b0; + end + + always @(Instruct or posedge start_autoboot or oe or current_state_event or + falling_edge_write or posedge PDONE or posedge WDONE or oe_z or + posedge EDONE or ERSSUSP_out or rising_edge_Reseted or + rising_edge_PoweredUp or rising_edge_CSNeg_ipd or PRGSUSP_out or + Address) + begin: Functionality + integer i,j; + integer sect; + + if (rising_edge_PoweredUp) + begin + //the default condition after power-up + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + //The Configuration Register FREEZE bit is cleared. + Config_reg1[0] = 0; + //The WEL bit is cleared. + Status_reg1[1] = 0; + //When BPNV is set to '1'. the BP2-0 bits in Status Register are + //volatile and will be reset binary 111 after power-on reset + if (BPNV == 1 && FREEZE == 0 ) //&& LOCK == 0 + begin + Status_reg1[4] = 1'b0;// BP2 + Status_reg1[3] = 1'b0;// BP1 + Status_reg1[2] = 1'b0;// BP0 + BP_bits = {Status_reg1[4],Status_reg1[3],Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + + //As shipped from the factory, all devices default ASP to the + //Persistent Protection mode, with all sectors unprotected, + //when power is applied. The device programmer or host system must + //then choose which sector protection method to use. + //For Persistent Protection mode, PPBLOCK defaults to "1" + PPBL[0] = 1'b1; + + //All the DYB power-up in the unprotected state + DYB_bits = {286{1'b1}}; + end + + if (Instruct == RESET) + begin + //EXTADD is cleared to “0” + Bank_Addr_reg[7] = 1'b0; + //P_ERR bit is cleared + Status_reg1[6] = 1'b0; + //E_ERR bit is cleared + Status_reg1[5] = 1'b0; + //The WEL bit is cleared. + Status_reg1[1] = 1'b0; + //The WIP bit is cleared. + Status_reg1[0] = 1'b0; + //The ES bit is cleared. + Status_reg2[1] = 1'b0; + //The PS bit is cleared. + Status_reg2[0] = 1'b0; + //When BPNV is set to '1'. the BP2-0 bits in Status + //Register are volatile and will be reseted after + //reset command + if (BPNV == 1 && FREEZE == 0) //&& LOCK== 0 + begin + Status_reg1[4] = 1'b1; + Status_reg1[3] = 1'b1; + Status_reg1[2] = 1'b1; + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + case (current_state) + IDLE : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + ASP_ProtSE = 0; + Sec_ProtSE = 0; + + if (BottomBoot) + begin + for (j=31;j>=0;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + else if (TopBoot) + begin + for (j=285;j>=254;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + + if (falling_edge_write && RdPswdProtMode == 1) + begin + if(Instruct == PASSU) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + end + + if (falling_edge_write && RdPswdProtMode == 0) + begin + read_cnt = 0; + byte_cnt = 1; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 0; + else if ((Instruct == WRR) && WEL == 1 && WDONE == 1 && + BAR_ACC == 0) + begin + if (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD) + begin + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + // P_ERR bit is set to 1 + Status_reg1[6] = 1'b1; + end + else + begin + // can not execute if Hardware Protection Mode + // is entered or if WEL bit is zero + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + end + else + Status_reg1[1] = 0; + end + else if ((Instruct == PP || Instruct == PP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if (Instruct == OTPP && WEL == 1) + begin + // As long as the FREEZE bit remains cleared to a logic + // '0' the OTP address space is programmable. + if (FREEZE == 0) + begin + if (((((Address>= 16'h0010 && Address<= 16'h0013) || + (Address >= 16'h0020 && Address <= 16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address >= 16'h0100 && Address <= 16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32] == 1) || + ((Address >= 16'h0200 && Address <= 16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32] == 1) || + ((Address >= 16'h0300 && Address <= 16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) && + (Address + Byte_number <= OTPHiAddr)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else if ((Address < 8'h10 || (Address > 8'h13 && + Address < 8'h20) || Address > 12'h3FF )) + begin + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + if (Address < 8'h20) + begin + $display ("Given address is "); + $display ("in reserved address range"); + end + else if (Address > 12'h3FF) + begin + $display ("Given address is "); + $display ("out of OTP address range"); + end + end + else + begin + //P_ERR bit will be set when the user attempts to + // to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == SE || Instruct == SE4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + SectorSuspend = sect; + PARAM_REGION = 0; + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((TopBoot && sect >= 254) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a 64 KB range + //that includes 4 KB sectors + begin + if (TopBoot) + begin + SectorSuspend = 254 + (285 - sect)/16; + end + else + begin + SectorSuspend = sect/16; + end + PARAM_REGION = 1; + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if ((Instruct == P4E || Instruct == P4E4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + Status_reg1[1] = 1'b0;//WEL + end + else + begin + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + //A P4E instruction applied to a sector + //that has been Write Protected through the + //Block Protect Bits or ASP will not be + //executed and will set the E_ERR status + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if (Instruct == BE && WEL == 1) + begin + if (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + end + else + begin + //The Bulk Erase command will not set E_ERR if a + //protected sector is found during the command + //execution. + Status_reg1[1] = 1'b0;//WEL + end + end + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + $display ("Password programming is not allowed"); + $display (" in Password Protection Mode."); + end + end + else if (Instruct == PASSU && WEL) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == ASPP && WEL == 1) + begin + if (~(ASPOTPFLAG)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + $display ("Once the Protection Mode is selected,"); + $display ("no further changes to the ASP "); + $display ("register is allowed."); + end + end + else if (Instruct == ABWR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBP && WEL == 1) + begin + ReturnSectorID(sect,Address); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBERS && WEL == 1) + begin + if (PPBOTP) + begin + PPBERASE_in = 1'b1; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[5] = 1'b1; + end + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PNVDLR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == WVDLR && WEL == 1) + begin + VDLR_reg = VDLR_reg_in; + Status_reg1[1] = 1'b0; + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4 || + Instruct == RES || + (Instruct == DLPRD && RdPswdProtMode == 0)) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4 || + ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + else if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ECCRD) + begin + //Read ECC Register + SOut_zd = ECCSR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) is enabled + // Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 0; + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + && QUAD) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) is enabled + // Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd = data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr + && RdPswdProtMode == 0) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + data_out[7:0] = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if ((read_addr > OTPHiAddr)||(RdPswdProtMode==1)) + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum or Read Password Protection Mode + //is selected instead, the data beyond the + //maximum OTP address will be undefined. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == REMS) + begin + //Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + data_out[7:0] = DeviceID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + else if (Instruct == RDID) + begin + ident_out = CFI_array_tmp; + if(read_cnt < 648) + begin + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + //Continued shifting of output beyond the end of + //the defined ID-CFI address space will + //provide undefined data. + SOut_zd = 1'bX; + end + end + else if (Instruct == RES) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + data_out = ESignature; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DLPRD && RdPswdProtMode == 0) + begin + //Read DLP + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = VDLR_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ABRD && RdPswdProtMode == 0) + begin + //Read AutoBoot register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = AutoBoot_reg_in[31-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 32) + read_cnt = 0; + end + else if (Instruct == BRRD && RdPswdProtMode == 0) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ASPRD && RdPswdProtMode == 0) + begin + //Read ASP Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = ASP_reg[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == PASSRD && RdPswdProtMode == 0) + begin + //Read Password Register + if (~(PWDMLB == 0 && PSTMLB == 1)) + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = + Password_reg[(8*byte_cnt-1)-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + byte_cnt = byte_cnt + 1; + if (byte_cnt == 9) + byte_cnt = 1; + end + end + end + else if (Instruct == PLBRD) + begin + //Read PPB Lock Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = PPBL[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + DYBAR[7:0] = 8'bXXXXXXXX; + + if (RdPswdProtMode == 0) + begin + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end + + AUTOBOOT: + begin + if (start_autoboot == 1) + begin + if (oe) + begin + any_read = 1'b1; + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + end + else if (oe_z) + begin + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + end + end + + WRITE_SR: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (WDONE == 1) + begin + Status_reg1[0] = 1'b0; //WIP + Status_reg1[1] = 1'b0; //WEL + //SRWD bit + Status_reg1[7] = Status_reg1_in[7]; //MSB first + +// if (LOCK == 0) +// begin + if (FREEZE == 0) + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT and TBPARM bits in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + begin + Status_reg1[4] = Status_reg1_in[4];//BP2 + Status_reg1[3] = Status_reg1_in[3];//BP1 + Status_reg1[2] = Status_reg1_in[2];//BP0 + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + if (TBPROT == 1'b0 && INITIAL_CONFIG == 1'b0) + begin + Config_reg1[5] = Config_reg1_in[5];//TBPROT + end + if (TBPARM == 1'b0 && INITIAL_CONFIG == 1'b0 && + tmp_char2 == "0") + begin + Config_reg1[2] = Config_reg1_in[2];//TBPARM + change_TBPARM = 1'b1; + #1000 change_TBPARM = 1'b0; + end + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end +// end + + Config_reg1[7] = Config_reg1_in[7];//LC1 + Config_reg1[6] = Config_reg1_in[6];//LC0 + Config_reg1[1] = Config_reg1_in[1];//QUAD + + if (FREEZE == 1'b0) + begin + Config_reg1[0] = Config_reg1_in[0];//FREEZE + end + +// if (WRLOCKENABLE== 1'b1 && LOCK == 1'b0) +// begin +// Config_reg1[4] = Config_reg1_in[4];//LOCK +// WRLOCKENABLE = 1'b0; +// end + if (BPNV == 1'b0) + begin + Config_reg1[3] = Config_reg1_in[3];//BPNV + end + end + end + + PAGE_PG : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == PAGE_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + Mem[Addr + i - cnt] = - 1; + if ((Addr + i) == AddrHi) + begin + + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt = 0; + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + quad_pg = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + PDONE = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns 3000000 ns = 3 us + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd =data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + OTP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == OTP_PG) + begin + if (~PDONE) + begin + if (Address + wr_cnt <= OTPHiAddr) + begin + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = OTPMem[Addr + i]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + OTPMem[Addr + i] = -1; + end + end + else + begin + $display ("Programming will reach over "); + $display ("address limit of OTP array"); + end + end + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + OTPMem[Addr + i] = WData[i]; + end + LOCK_BYTE1 = OTPMem[16]; + LOCK_BYTE2 = OTPMem[17]; + LOCK_BYTE3 = OTPMem[18]; + LOCK_BYTE4 = OTPMem[19]; + end + end + + SECTOR_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == SECTOR_ERS) + begin + if (~EDONE) + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + + pgm_page = i / (PageSize+1); + end + end + else if (Instruct == ERSP && ~ERSSUSP_in) + begin + ESUSP = 1'b1; + ESUSP <= #5 1'b0; + ERSSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + end + + BULK_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == BULK_ERS) + begin + if (~EDONE) + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = -1; + end + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = MaxData; + + pgm_page = i / (PageSize+1); + end + end + end + end + + ERS_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (ERSSUSP_out == 1) + begin + ERSSUSP_in = 0; + //The Erase Suspend (ES) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //erase operation has been suspended. + Status_reg2[1] = 1'b1; + //The WIP bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == PP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == ERRS) + begin + Status_reg2[1] = 1'b0; + Status_reg1[0] = 1'b1; + if (BottomBoot) + begin + if (PARAM_REGION) + begin + Addr = SectorSuspend*(SecSize+1); + end + else + begin + Addr = (SectorSuspend-30)*(SecSize+1); + end + end + else + begin + Addr = SectorSuspend*(SecSize+1); + end + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + ERES = 1'b1; + ERES <= #5 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == ERS_SUSP_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt =0; + end + + if(PDONE == 1) + begin + Status_reg1[0] = 1'b0;//WIP + Status_reg1[1] = 1'b0;//WEL + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi ) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PASS_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + new_pass = Password_reg_in; + old_pass = Password_reg; + for (i=0;i<=63;i=i+1) + begin + if (old_pass[j] == 0) + new_pass[j] = 0; + end + + if (PDONE == 1) + begin + Password_reg = new_pass; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PASS_UNLOCK: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PASS_TEMP == Password_reg) + begin + PASS_UNLOCKED = 1'b1; + end + else + begin + PASS_UNLOCKED = 1'b0; + end + if (PASSULCK_out == 1'b1) + begin + if ((PASS_UNLOCKED == 1'b1) && (~PWDMLB)) + begin + PPBL[0] = 1'b1; + Status_reg1[0] = 1'b0; //WIP + end + else + begin + Status_reg1[6] = 1'b1; + $display ("Incorrect Password"); + PASSACC_in = 1'b1; + end + Status_reg1[1] = 1'b0; + PASSULCK_in = 1'b0; + end + end + + PPB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (PPB_LOCK !== 0) + begin + PPB_bits[sect]= 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[5] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + end + + PPB_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PPBERASE_out == 1'b1) + begin + if ((PPB_LOCK !== 0) && PPBOTP) + begin + PPB_bits = {286{1'b1}}; + end + else + begin + Status_reg1[5] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + PPBERASE_in = 1'b0; + end + end + + AUTOBOOT_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + for(i=0;i<=3;i=i+1) + for(j=0;j<=7;j=j+1) + AutoBoot_reg[i*8+j] = + AutoBoot_reg_in[(3-i)*8+j]; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PLB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + PPBL[0] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + DYB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + DYBAR = DYBAR_in; + if (DYBAR == 8'hFF) + begin + DYB_bits[sect]= 1'b1; + end + else if (DYBAR == 8'h00) + begin + DYB_bits[sect]= 1'b0; + end + else + begin + Status_reg1[6] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + ASP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + + if (RPME == 1'b0 && ASP_reg_in[5] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("RPME bit is allready programmed"); + end + else + begin + ASP_reg[5] = ASP_reg_in[5];//RPME + end + + if (PPBOTP == 1'b0 && ASP_reg_in[3] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("PPBOTP bit is allready programmed"); + end + else + begin + ASP_reg[3] = ASP_reg_in[3];//PPBOTP + end + + if (PWDMLB == 1'b1 && PSTMLB == 1'b1) + begin + if (ASP_reg_in[2] == 1'b0 && ASP_reg_in[1] == 1'b0) + begin + $display("ASPR[2:1] = 00 Illegal condition"); + Status_reg1[6] = 1'b1; //P_ERR + end + else + begin + if (ASP_reg_in[2]!==1'b1 || ASP_reg_in[1]!==1'b1) + begin + ASPOTPFLAG = 1'b1; + end + ASP_reg[2] = ASP_reg_in[2];//PWDMLB + ASP_reg[1] = ASP_reg_in[1];//PSTMLB + end + end + + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + NVDLR_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (NVDLR_reg == 0) + begin + NVDLR_reg = NVDLR_reg_in; + VDLR_reg = NVDLR_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; //P_ERR + $display("NVDLR bits allready programmed"); + end + end + end + + RESET_STATE: + begin + //the default condition hardware reset + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + if (BPNV && ~FREEZE) //&& ~LOCK + begin + Status_reg1[2] = 1'b1;// BP0 + Status_reg1[3] = 1'b1;// BP1 + Status_reg1[4] = 1'b1;// BP2 + BP_bits = 3'b111; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + //Resets the volatile bits in the Status register 1 + Status_reg1[6] = 1'b0; + Status_reg1[5] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[0] = 1'b0; + //Resets the volatile bits in the Status register 2 + Status_reg2[1] = 1'b0; + Status_reg2[0] = 1'b0; + //Resets the volatile bits in the Configuration register 1 + Config_reg1[0] = 1'b0; + //On reset cycles the data pattern reverts back + //to what is in the NVDLR + VDLR_reg = NVDLR_reg; + start_dlp = 1'b0; + //Loads the Program Buffer with all ones + for(i=0;i<=511;i=i+1) + begin + WData[i] = MaxData; + end + if (~PWDMLB) + PPBL[0] = 1'b0; + else + PPBL[0] = 1'b1; + end + + endcase + + //Output Disable Control + if (CSNeg_ipd ) + begin + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign ddrd = ddr && ~ddr80; + assign ddrd80 = ddr && ddr80; + assign fast_ddr = ddr_fast; + + always @(change_TBPARM, posedge PoweredUp) + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + BottomBoot = 1; + b_act = 1; + end + else + begin + TopBoot = 1; + BottomBoot = 0; + b_act = 0; + end + end + else if (tmp_char2 == "1") + begin + UniformSec = 1; + end + end + + always @(posedge change_BP) + begin + case (Status_reg1[4:2]) + + 3'b000: + Sec_Prot[285:0] = {286{1'b0}}; + + 3'b001: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256:(SecNum256+1)*63/64] = 1'b1; + Sec_Prot[(SecNum256+1)*63/64-1 : 0] = {63{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/64-1 : 0] = 1'b1; + Sec_Prot[SecNum256 : (SecNum256+1)/64] = {63{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64] = {34{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64-1 : 0] = {252{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/64-1 : 0] = {4{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64] = {282{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64+30] = {4{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64+29 : 0] = {282{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/64+29 : 0] = {34{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64+30] = {252{1'b0}}; + end + end + end + + 3'b010: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*31/32] = {2{1'b1}}; + Sec_Prot[(SecNum256+1)*31/32-1 : 0] = {62{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/32-1 : 0] = {2{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/32] = {62{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*31/32] = {38{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32-1 : 0] = {248{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/32-1 : 0] = {8{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32] = {278{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*31/32+30] = {8{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32+29 : 0] = {278{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/32+29 : 0] = {38{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32+30] = {248{1'b0}}; + end + end + end + + 3'b011: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*15/16] = 4'b1111; + Sec_Prot[(SecNum256+1)*15/16-1 : 0] = {60{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/16-1 : 0] = 4'b1111; + Sec_Prot[SecNum256 : (SecNum256+1)/16] = {60{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16] = {46{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16-1 : 0] = {240{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/16-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16] = {270{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16+30] ={16{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16+29 : 0] = {270{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/16+29 : 0] ={46{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16+30] = {240{1'b0}}; + end + end + end + + 3'b100: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*7/8] = {8{1'b1}}; + Sec_Prot[(SecNum256+1)*7/8-1 : 0] = {278{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/8-1 : 0] = {8{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/8] = {278{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8] = {62{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8-1 : 0] = {224{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/8-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8] = {254{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8+30] ={32{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8+29 : 0] = {254{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/8+29 : 0] = {62{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8+30] = {224{1'b0}}; + end + end + end + + 3'b101: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*3/4] = {16{1'b1}}; + Sec_Prot[(SecNum256+1)*3/4-1 : 0] = {270{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/4-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/4] = {270{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4] = {94{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4-1 : 0] = {192{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/4-1 : 0] = {64{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4] = {222{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4+30] = {64{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4+29 : 0] = {222{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/4+29 : 0] = {94{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4+30] = {192{1'b0}}; + end + end + end + + 3'b110: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)/2] = {32{1'b1}}; + Sec_Prot[(SecNum256+1)/2-1 : 0] = {32{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/2-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/2] = {32{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2] = {158{1'b1}}; + Sec_Prot[(SecNum64-29)/2-1 : 0] = {128{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/2-1 : 0] = {128{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2] = {158{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = {128{1'b1}}; + Sec_Prot[(SecNum64-29)/2+29 : 0] = {158{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/2+29 : 0] = {158{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = {128{1'b0}}; + end + end + end + + 3'b111: + begin + Sec_Prot[SecNum64:0] = {286{1'b1}}; + end + endcase + end + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // autoboot control logic + //////////////////////////////////////////////////////////////////////// + always @(rising_edge_SCK_ipd or current_state_event) + begin + if(current_state == AUTOBOOT) + begin + if (rising_edge_SCK_ipd) + begin + if (start_delay > 0) + start_delay = start_delay - 1; + end + + if (start_delay == 0) + begin + start_autoboot = 1; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure FDDR_DPL +task Return_DLP; + input integer Instruct; + input integer EHP; + input integer Latency_code; + input integer dummy_cnt; + inout start_dlp; + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + if (EHP) + begin + if (Latency_code == 1) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 1) + start_dlp = 1'b1; + else if(Latency_code == 3 || Latency_code == 0) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + + if (Latency_code == 3) + start_dlp = 1'b1; + else if (Latency_code == 0 && dummy_cnt >= 1) + start_dlp = 1'b1; + else if(Latency_code == 1 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 3) + start_dlp = 1'b1; + else + start_dlp = 1'b0; + end + end + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + if (EHP) + begin + if (Latency_code == 1 && dummy_cnt >= 1) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if( Latency_code == 3 || Latency_code == 0) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + else + start_dlp = 1'b0; + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + start_dlp = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 4) + start_dlp = 1'b1; + else + start_dlp = 1'b0; + end + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && QUAD) + begin + if (EHP) + begin + if (Latency_code == 0 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + start_dlp = 1'b1; + else if( Latency_code == 3) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + else + start_dlp = 1'b0; + + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + start_dlp = 1'b1; + else if( Latency_code == 3) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + else + start_dlp = 1'b0; + end + end + end + endtask + + function integer ReturnSectorIDRdPswdMd; + input reg TBPROT; + begin + if(TBPROT == 0) + begin + ReturnSectorIDRdPswdMd = 0; + end + else + begin + if (UniformSec) + begin + ReturnSectorIDRdPswdMd = SecNum256; + end + else + begin + ReturnSectorIDRdPswdMd = 255; + end + end + end + endfunction + + // Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + if (Addr/(SecSize64+1) <= 1 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = Addr/(SecSize4+1); + AddrLOW = sector*(SecSize4+1); + AddrHIGH = sector*(SecSize4+1) + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + else + begin + if (Addr/(SecSize64+1) >= 254 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = 254 + (Addr-(SecSize64+1)*254)/(SecSize4+1); + AddrLOW = 254*(SecSize64+1)+(sector-254)*(SecSize4+1); + AddrHIGH = 254*(SecSize64+1)+(sector-254)*(SecSize4+1) + + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + end + else if (tmp_char2 == "1") + begin + sector = Addr/(SecSize256+1); + AddrLOW = sector*(SecSize256+1); + AddrHIGH = sector*(SecSize256+1) + SecSize256; + end + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / (PageSize + 1); + AddrLOW = page * (PageSize + 1); + AddrHIGH = page * (PageSize + 1) + PageSize ; + end + endtask + + // Procedure ReturnSectorID + task ReturnSectorID; + inout sect; + input Address; + integer sect; + integer Address; + integer conv; + begin + if (tmp_char2 == "0") + begin + conv = Address / (SecSize64+1); + if (BottomBoot) + begin + if (conv <= 1) //4KB Sectors + begin + sect = Address/(SecSize4+1); + end + else + begin + sect = conv + 30; + end + end + else if (TopBoot) + begin + if (conv >= 254) //4KB Sectors + begin + sect = 254 + (Address-(SecSize64+1)*254)/(SecSize4+1); + end + else + begin + sect = conv; + end + end + end + else + begin + sect = Address/(SecSize256+1); + end + end + endtask + + always @(PPBL[0], ASP_reg) + begin + if (PPBL[0] == 0 && PWDMLB == 0 && RPME == 0 && RdPswdProtEnable) + begin + RdPswdProtMode = 1; + AutoBoot_reg[0] = 0;//AUTOBOOT is disabled when Read Password + end //Protection is enabled + else + begin + RdPswdProtMode = 0; + end + end + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1; + #1000 falling_edge_write = 0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge RSTNeg_in) + begin + falling_edge_RSTNeg = 1'b1; + #50000 falling_edge_RSTNeg = 1'b0; + end + + always @(posedge RSTNeg_in) + begin + rising_edge_RSTNeg = 1'b1; + #10000 rising_edge_RSTNeg = 1'b0; + end + + always @(negedge RST) + begin + falling_edge_RST = 1'b1; + #10000 falling_edge_RST = 1'b0; + end + + always @(posedge RST) + begin + rising_edge_RST = 1'b1; + #1000 rising_edge_RST = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge Reseted) + begin + rising_edge_Reseted = 1'b1; + #1000 rising_edge_Reseted = 1'b0; + end + + always @(negedge PASSULCK_in) + begin + falling_edge_PASSULCK_in = 1'b1; + #1000 falling_edge_PASSULCK_in = 1'b0; + end + + always @(negedge PPBERASE_in) + begin + falling_edge_PPBERASE_in = 1'b1; + #1000 falling_edge_PPBERASE_in = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge RST_out) + begin + rising_edge_RST_out = 1'b1; + #1000 rising_edge_RST_out = 1'b0; + end + +endmodule diff --git a/sim/top_freertos_tb.v b/sim/top_freertos_tb.v new file mode 100644 index 0000000..3383ad8 --- /dev/null +++ b/sim/top_freertos_tb.v @@ -0,0 +1,68 @@ +/* This file implements a test that is able to execute programs stored on the + * host file system. + */ + +`default_nettype none + +`timescale 1ns/1ps + +module top_freertos_tb; + +reg clk; +reg btn_n; +reg btn1; +wire led1; +wire led2; +wire flash_sck; +wire flash_ssb; +wire flash_io0; +wire flash_io1; + +top_freertos dut( + .CLK(clk), + .BTN_N(btn_n), + .BTN1(btn1), + .LED1(led1), + .LED2(led2), + .FLASH_SCK(flash_sck), + .FLASH_SSB(flash_ssb), + .FLASH_IO0(flash_io0), + .FLASH_IO1(flash_io1) +); + +s25fl128s + #(.mem_file_name ("crush_freertos.data"), + .AddrRANGE (24'h2F_FFFF)) +flash + ( + .SCK (flash_sck), + .SI (flash_io0), + .CSNeg (flash_ssb), + .HOLDNeg (), //Internal pull-up + .WPNeg (), //Internal pull-up + .SO (flash_io1), + .RSTNeg (1'b1)); + +initial begin + btn_n = 0; + // Wait for flash to power up + #500_000 btn_n = 1; +end + +initial clk = 0; +always #80 clk <= !clk; + +initial btn1 = 0; +always #10_000_000 btn1 <= !btn1; + +initial begin + $dumpfile("top_freertos.vcd"); + $dumpvars(0); + + #(1_300_000_000) + + $display("finishing now"); + $finish; +end + +endmodule diff --git a/tools/freertos_top.gtkw b/tools/freertos_top.gtkw new file mode 100644 index 0000000..07080d4 --- /dev/null +++ b/tools/freertos_top.gtkw @@ -0,0 +1,60 @@ +[*] +[*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI +[*] Tue Dec 10 15:40:39 2024 +[*] +[dumpfile] "/home/barabas/data3/projects/hardware/risc-v/build/crush_0.0.1/sim_top_freertos-icarus/top_freertos.vcd" +[dumpfile_mtime] "Tue Dec 10 15:38:03 2024" +[dumpfile_size] 38981521 +[savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/freertos_top.gtkw" +[timestart] 879600000000 +[size] 2560 1371 +[pos] -1 -1 +*-35.443504 1241200000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] top_freertos_tb. +[treeopen] top_freertos_tb.dut. +[treeopen] top_freertos_tb.dut.ram.memory. +[sst_width] 447 +[signals_width] 290 +[sst_expanded] 1 +[sst_vpaned_height] 425 +@200 +-flash +@28 +top_freertos_tb.dut.FLASH_IO0 +top_freertos_tb.dut.FLASH_IO1 +top_freertos_tb.dut.FLASH_SCK +top_freertos_tb.dut.FLASH_SSB +@200 +-wb +@22 +top_freertos_tb.dut.dat_o[31:0] +top_freertos_tb.dut.adr_o[31:0] +top_freertos_tb.dut.dat_i[31:0] +top_freertos_tb.dut.sel_o[3:0] +@200 +-spi +@22 +top_freertos_tb.dut.spi.address[31:0] +@200 +-RAM +@22 +top_freertos_tb.dut.ram.adr_i[31:0] +top_freertos_tb.dut.ram.dat_i[31:0] +top_freertos_tb.dut.ram.dat_o[31:0] +@28 +top_freertos_tb.dut.ram.we_i +top_freertos_tb.dut.ram.ack_o +@200 +- +@22 +top_freertos_tb.dut.boot_rom.g_scope[0].m[31:0] +top_freertos_tb.dut.boot_rom.g_scope[1].m[31:0] +top_freertos_tb.dut.boot_rom.adr_i[31:0] +top_freertos_tb.dut.boot_rom.dat_o[31:0] +@28 +top_freertos_tb.btn1 +top_freertos_tb.btn_n +top_freertos_tb.led1 +top_freertos_tb.led2 +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/tools/freertos_top_debug.gtkw b/tools/freertos_top_debug.gtkw new file mode 100644 index 0000000..a18fa3c --- /dev/null +++ b/tools/freertos_top_debug.gtkw @@ -0,0 +1,40 @@ +[*] +[*] GTKWave Analyzer v3.3.120 (w)1999-2024 BSI +[*] Tue Jan 21 16:23:16 2025 +[*] +[dumpfile] "/home/barabas/data3/projects/hardware/risc-v/build/crush_0.0.1/sim_top_freertos-icarus/top_freertos.vcd" +[dumpfile_mtime] "Tue Jan 21 16:16:56 2025" +[dumpfile_size] 38982023 +[savefile] "/home/barabas/data3/projects/hardware/risc-v/tools/freertos_top_debug.gtkw" +[timestart] 0 +[size] 2560 1371 +[pos] -1 -1 +*-34.057491 2860000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] top_freertos_tb. +[treeopen] top_freertos_tb.dut. +[sst_width] 273 +[signals_width] 207 +[sst_expanded] 1 +[sst_vpaned_height] 425 +@28 +top_freertos_tb.clk +top_freertos_tb.btn1 +top_freertos_tb.btn_n +top_freertos_tb.led1 +top_freertos_tb.led2 +top_freertos_tb.flash_io0 +top_freertos_tb.flash_io1 +top_freertos_tb.flash_sck +top_freertos_tb.flash_ssb +@200 +-BUS +@28 +top_freertos_tb.dut.ack_i +@22 +top_freertos_tb.dut.adr_o[31:0] +@200 +-PC +@22 +top_freertos_tb.dut.cpu.pc[31:0] +[pattern_trace] 1 +[pattern_trace] 0 From 17691dd0f06b79c3dc20bf776919e4461295bc89 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 11:55:50 +0000 Subject: [PATCH 47/88] clean up SPI bootloader --- boot_fw/boot.S | 48 ------------------------------------------------ 1 file changed, 48 deletions(-) diff --git a/boot_fw/boot.S b/boot_fw/boot.S index 3036440..62d3fe2 100644 --- a/boot_fw/boot.S +++ b/boot_fw/boot.S @@ -60,44 +60,16 @@ spi_init: li a0, ((APP_FLASH_ADDR & 0xFF) <<24) | ((APP_FLASH_ADDR & 0xFF00) << 8) | ((APP_FLASH_ADDR & 0xFF0000) >> 8) | 0x3 jal spi_xfer - /* Get magic word */ - // TODO maybe need this read for this whole thing to work correctly - // jal spi_xfer - read_header: - // TODO do not read a header, use the compile time constant for this configuration - /* Dummy read two words */ - //jal spi_xfer - //jal spi_xfer - /* Load image size to s0 */ - //jal spi_xfer - //jal endian_swap li s0, APP_SIZE /* Load RAM base address to s1 */ - //jal spi_xfer - //jal endian_swap li s1, APP_SRAM_ADDR /* Load reset vector to s2 */ - //jal spi_xfer - //jal endian_swap li s2, APP_SRAM_ADDR - /* Dummy read rest of header */ - //jal spi_xfer //dcrc - //jal spi_xfer //os, arch, type, comp - - //jal spi_xfer - //jal spi_xfer - //jal spi_xfer - //jal spi_xfer - //jal spi_xfer - //jal spi_xfer - //jal spi_xfer - //jal spi_xfer - /* Clear number of copied bytes */ addi s4, zero, 0 copy_to_ram: @@ -119,26 +91,6 @@ copy_to_ram: goto_reset: jr s2 - /* Reads ddccbbaa from a1, stores aabbccdd to a2 */ - /* -endian_swap: - slli a2, a1, 24 // a2 = aa000000 - srli t1, a1, 8 // t1 = 00ddccbb - andi t1, t1, 0xff // t1 = 000000bb - slli t1, t1, 16 // t1 = 00bb0000 - or a2, a2, t1 // a2 = aabb0000 - - srli t1, a1, 16 // t1 = 0000ddcc - andi t1, t1, 0xff // t1 = 000000cc - slli t1, t1, 8 // t1 = 0000cc00 - or a2, a2, t1 // a2 = aabbcc00 - - srli t1, a1, 24 // t1 = 000000dd - or a2, a2, t1 // a2 = aabbccdd - - ret - */ - spi_xfer: /* Loop four times */ addi t0, zero, 4 From f47b214ca3951555d657bd1c2b3bc362eab356d6 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 11:58:03 +0000 Subject: [PATCH 48/88] fix iceprog hints --- crush.core | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/crush.core b/crush.core index 4ffd77f..d46f67d 100644 --- a/crush.core +++ b/crush.core @@ -136,7 +136,7 @@ targets: - "-gassertions" - "-DSIM" hooks: - post_run: [iceprog_hint] + post_run: [iceprog_bitstream_hint] top_freertos: <<: *default @@ -146,7 +146,7 @@ targets: - pcf toplevel: top_freertos hooks: - post_run: [iceprog_hint_freertos] + post_run: [iceprog_app_hint] lint: default_tool : verilator @@ -253,7 +253,11 @@ targets: default_tool: icarus scripts: - iceprog_hint: + iceprog_bitstream_hint: + cmd: + - echo + - "Run 'iceprog -o 0x20000 freertos/app/build/crush_freertos.bin' to load firmware to flash." + iceprog_app_hint: cmd: - echo - "Run 'iceprog -o 0x20000 freertos/app/build/crush_freertos.bin' to load firmware to flash." From 5a56d59e0f5c1eed4c50f1555fd1d5f5c9d31b80 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 12:07:08 +0000 Subject: [PATCH 49/88] remove debug script --- dump-firmware.sh | 1 - 1 file changed, 1 deletion(-) delete mode 100755 dump-firmware.sh diff --git a/dump-firmware.sh b/dump-firmware.sh deleted file mode 100755 index 86961b4..0000000 --- a/dump-firmware.sh +++ /dev/null @@ -1 +0,0 @@ -riscv64-elf-objdump -S -Mnumeric freertos/app/build/crush_freertos | less From a2654638015140bc948b5919fad86f65a5ba35d2 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 12:07:17 +0000 Subject: [PATCH 50/88] clean up freertos config --- .../freertos_config/include/FreeRTOSConfig.h | 342 ------------------ 1 file changed, 342 deletions(-) diff --git a/freertos/app/freertos_config/include/FreeRTOSConfig.h b/freertos/app/freertos_config/include/FreeRTOSConfig.h index be2b106..3fcb807 100644 --- a/freertos/app/freertos_config/include/FreeRTOSConfig.h +++ b/freertos/app/freertos_config/include/FreeRTOSConfig.h @@ -1,396 +1,63 @@ -/* - * FreeRTOS Kernel V11.1.0 - * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * https://www.FreeRTOS.org - * https://github.com/FreeRTOS - * - */ - -/******************************************************************************* - * This file provides an example FreeRTOSConfig.h header file, inclusive of an - * abbreviated explanation of each configuration item. Online and reference - * documentation provides more information. - * https://www.freertos.org/a00110.html - * - * Constant values enclosed in square brackets ('[' and ']') must be completed - * before this file will build. - * - * Use the FreeRTOSConfig.h supplied with the RTOS port in use rather than this - * generic file, if one is available. - ******************************************************************************/ - #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H -/******************************************************************************/ -/* Hardware description related definitions. **********************************/ -/******************************************************************************/ - -/* In most cases, configCPU_CLOCK_HZ must be set to the frequency of the clock - * that drives the peripheral used to generate the kernels periodic tick interrupt. - * The default value is set to 20MHz and matches the QEMU demo settings. Your - * application will certainly need a different value so set this correctly. - * This is very often, but not always, equal to the main system clock frequency. */ #define configCPU_CLOCK_HZ ( ( unsigned long ) 12000000 ) -/******************************************************************************/ -/* Scheduling behaviour related definitions. **********************************/ -/******************************************************************************/ - -/* configTICK_RATE_HZ sets frequency of the tick interrupt in Hz, normally - * calculated from the configCPU_CLOCK_HZ value. */ #define configTICK_RATE_HZ 100 - -/* Set configUSE_PREEMPTION to 1 to use pre-emptive scheduling. Set - * configUSE_PREEMPTION to 0 to use co-operative scheduling. - * See https://www.freertos.org/single-core-amp-smp-rtos-scheduling.html. */ #define configUSE_PREEMPTION 1 - -/* Set configUSE_TIME_SLICING to 1 to have the scheduler switch between Ready - * state tasks of equal priority on every tick interrupt. Set - * configUSE_TIME_SLICING to 0 to prevent the scheduler switching between Ready - * state tasks just because there was a tick interrupt. See - * https://freertos.org/single-core-amp-smp-rtos-scheduling.html. */ #define configUSE_TIME_SLICING 0 - -/* Set configUSE_PORT_OPTIMISED_TASK_SELECTION to 1 to select the next task to - * run using an algorithm optimised to the instruction set of the target hardware - - * normally using a count leading zeros assembly instruction. Set to 0 to select - * the next task to run using a generic C algorithm that works for all FreeRTOS - * ports. Not all FreeRTOS ports have this option. Defaults to 0 if left - * undefined. */ #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 - -/* Set configUSE_TICKLESS_IDLE to 1 to use the low power tickless mode. Set to - * 0 to keep the tick interrupt running at all times. Not all FreeRTOS ports - * support tickless mode. See https://www.freertos.org/low-power-tickless-rtos.html - * Defaults to 0 if left undefined. */ #define configUSE_TICKLESS_IDLE 0 - -/* configMAX_PRIORITIES Sets the number of available task priorities. Tasks can - * be assigned priorities of 0 to (configMAX_PRIORITIES - 1). Zero is the lowest - * priority. */ #define configMAX_PRIORITIES 5 - -/* configMINIMAL_STACK_SIZE defines the size of the stack used by the Idle task - * (in words, not in bytes!). The kernel does not use this constant for any other - * purpose. Demo applications use the constant to make the demos somewhat portable - * across hardware architectures. */ #define configMINIMAL_STACK_SIZE 128 - -/* configMAX_TASK_NAME_LEN sets the maximum length (in characters) of a task's - * human readable name. Includes the NULL terminator. */ #define configMAX_TASK_NAME_LEN 16 - -/* Time is measured in 'ticks' - which is the number of times the tick interrupt - * has executed since the RTOS kernel was started. - * The tick count is held in a variable of type TickType_t. - * - * configTICK_TYPE_WIDTH_IN_BITS controls the type (and therefore bit-width) of TickType_t: - * - * Defining configTICK_TYPE_WIDTH_IN_BITS as TICK_TYPE_WIDTH_16_BITS causes - * TickType_t to be defined (typedef'ed) as an unsigned 16-bit type. - * - * Defining configTICK_TYPE_WIDTH_IN_BITS as TICK_TYPE_WIDTH_32_BITS causes - * TickType_t to be defined (typedef'ed) as an unsigned 32-bit type. - * - * Defining configTICK_TYPE_WIDTH_IN_BITS as TICK_TYPE_WIDTH_64_BITS causes - * TickType_t to be defined (typedef'ed) as an unsigned 64-bit type. */ #define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_64_BITS - -/* Set configIDLE_SHOULD_YIELD to 1 to have the Idle task yield to an - * application task if there is an Idle priority (priority 0) application task that - * can run. Set to 0 to have the Idle task use all of its timeslice. Default to 1 - * if left undefined. */ #define configIDLE_SHOULD_YIELD 1 - -/* Each task has an array of task notifications. - * configTASK_NOTIFICATION_ARRAY_ENTRIES sets the number of indexes in the array. - * See https://www.freertos.org/RTOS-task-notifications.html Defaults to 1 if - * left undefined. */ #define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 - -/* configQUEUE_REGISTRY_SIZE sets the maximum number of queues and semaphores - * that can be referenced from the queue registry. Only required when using a - * kernel aware debugger. Defaults to 0 if left undefined. */ #define configQUEUE_REGISTRY_SIZE 0 - -/* Set configENABLE_BACKWARD_COMPATIBILITY to 1 to map function names and - * datatypes from old version of FreeRTOS to their latest equivalent. Defaults to - * 1 if left undefined. */ #define configENABLE_BACKWARD_COMPATIBILITY 0 - -/* Each task has its own array of pointers that can be used as thread local - * storage. configNUM_THREAD_LOCAL_STORAGE_POINTERS set the number of indexes in - * the array. See https://www.freertos.org/thread-local-storage-pointers.html - * Defaults to 0 if left undefined. */ #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 - -/* When configUSE_MINI_LIST_ITEM is set to 0, MiniListItem_t and ListItem_t are - * both the same. When configUSE_MINI_LIST_ITEM is set to 1, MiniListItem_t contains - * 3 fewer fields than ListItem_t which saves some RAM at the cost of violating - * strict aliasing rules which some compilers depend on for optimization. Defaults - * to 1 if left undefined. */ #define configUSE_MINI_LIST_ITEM 1 - -/* Sets the type used by the parameter to xTaskCreate() that specifies the stack - * size of the task being created. The same type is used to return information - * about stack usage in various other API calls. Defaults to size_t if left - * undefined. */ #define configSTACK_DEPTH_TYPE size_t - -/* configMESSAGE_BUFFER_LENGTH_TYPE sets the type used to store the length of - * each message written to a FreeRTOS message buffer (the length is also written to - * the message buffer. Defaults to size_t if left undefined - but that may waste - * space if messages never go above a length that could be held in a uint8_t. */ #define configMESSAGE_BUFFER_LENGTH_TYPE size_t - -/* If configHEAP_CLEAR_MEMORY_ON_FREE is set to 1, then blocks of memory allocated - * using pvPortMalloc() will be cleared (i.e. set to zero) when freed using - * vPortFree(). Defaults to 0 if left undefined. */ #define configHEAP_CLEAR_MEMORY_ON_FREE 1 - -/* vTaskList and vTaskGetRunTimeStats APIs take a buffer as a parameter and assume - * that the length of the buffer is configSTATS_BUFFER_MAX_LENGTH. Defaults to - * 0xFFFF if left undefined. - * New applications are recommended to use vTaskListTasks and - * vTaskGetRunTimeStatistics APIs instead and supply the length of the buffer - * explicitly to avoid memory corruption. */ #define configSTATS_BUFFER_MAX_LENGTH 0xFFFF - -/* Set configUSE_NEWLIB_REENTRANT to 1 to have a newlib reent structure - * allocated for each task. Set to 0 to not support newlib reent structures. - * Default to 0 if left undefined. - * - * Note Newlib support has been included by popular demand, but is not used or - * tested by the FreeRTOS maintainers themselves. FreeRTOS is not responsible for - * resulting newlib operation. User must be familiar with newlib and must provide - * system-wide implementations of the necessary stubs. Note that (at the time of - * writing) the current newlib design implements a system-wide malloc() that must - * be provided with locks. */ #define configUSE_NEWLIB_REENTRANT 0 -/******************************************************************************/ -/* Software timer related definitions. ****************************************/ -/******************************************************************************/ - -/* Set configUSE_TIMERS to 1 to include software timer functionality in the - * build. Set to 0 to exclude software timer functionality from the build. The - * FreeRTOS/source/timers.c source file must be included in the build if - * configUSE_TIMERS is set to 1. Default to 0 if left undefined. See - * https://www.freertos.org/RTOS-software-timer.html. */ #define configUSE_TIMERS 1 - -/* configTIMER_TASK_PRIORITY sets the priority used by the timer task. Only - * used if configUSE_TIMERS is set to 1. The timer task is a standard FreeRTOS - * task, so its priority is set like any other task. See - * https://www.freertos.org/RTOS-software-timer-service-daemon-task.html Only used - * if configUSE_TIMERS is set to 1. */ #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) - -/* configTIMER_TASK_STACK_DEPTH sets the size of the stack allocated to the - * timer task (in words, not in bytes!). The timer task is a standard FreeRTOS - * task. See https://www.freertos.org/RTOS-software-timer-service-daemon-task.html - * Only used if configUSE_TIMERS is set to 1. */ #define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE - -/* configTIMER_QUEUE_LENGTH sets the length of the queue (the number of discrete - * items the queue can hold) used to send commands to the timer task. See - * https://www.freertos.org/RTOS-software-timer-service-daemon-task.html Only used - * if configUSE_TIMERS is set to 1. */ #define configTIMER_QUEUE_LENGTH 10 -/******************************************************************************/ -/* Event Group related definitions. *******************************************/ -/******************************************************************************/ - -/* Set configUSE_EVENT_GROUPS to 1 to include event group functionality in the - * build. Set to 0 to exclude event group functionality from the build. The - * FreeRTOS/source/event_groups.c source file must be included in the build if - * configUSE_EVENT_GROUPS is set to 1. Defaults to 1 if left undefined. */ - #define configUSE_EVENT_GROUPS 0 -/******************************************************************************/ -/* Stream Buffer related definitions. *****************************************/ -/******************************************************************************/ - -/* Set configUSE_STREAM_BUFFERS to 1 to include stream buffer functionality in - * the build. Set to 0 to exclude event group functionality from the build. The - * FreeRTOS/source/stream_buffer.c source file must be included in the build if - * configUSE_STREAM_BUFFERS is set to 1. Defaults to 1 if left undefined. */ - #define configUSE_STREAM_BUFFERS 0 -/******************************************************************************/ -/* Memory allocation related definitions. *************************************/ -/******************************************************************************/ - -/* Set configSUPPORT_STATIC_ALLOCATION to 1 to include FreeRTOS API functions - * that create FreeRTOS objects (tasks, queues, etc.) using statically allocated - * memory in the build. Set to 0 to exclude the ability to create statically - * allocated objects from the build. Defaults to 0 if left undefined. See - * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */ #define configSUPPORT_STATIC_ALLOCATION 1 #define configKERNEL_PROVIDED_STATIC_MEMORY 1 - -/* Set configSUPPORT_DYNAMIC_ALLOCATION to 1 to include FreeRTOS API functions - * that create FreeRTOS objects (tasks, queues, etc.) using dynamically allocated - * memory in the build. Set to 0 to exclude the ability to create dynamically - * allocated objects from the build. Defaults to 1 if left undefined. See - * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */ #define configSUPPORT_DYNAMIC_ALLOCATION 0 - -/* Sets the total size of the FreeRTOS heap, in bytes, when heap_1.c, heap_2.c - * or heap_4.c are included in the build. This value is defaulted to 4096 bytes but - * it must be tailored to each application. Note the heap will appear in the .bss - * section. See https://www.freertos.org/a00111.html. */ #define configTOTAL_HEAP_SIZE 4096 - -/* Set configAPPLICATION_ALLOCATED_HEAP to 1 to have the application allocate - * the array used as the FreeRTOS heap. Set to 0 to have the linker allocate the - * array used as the FreeRTOS heap. Defaults to 0 if left undefined. */ #define configAPPLICATION_ALLOCATED_HEAP 0 - -/* Set configSTACK_ALLOCATION_FROM_SEPARATE_HEAP to 1 to have task stacks - * allocated from somewhere other than the FreeRTOS heap. This is useful if you - * want to ensure stacks are held in fast memory. Set to 0 to have task stacks - * come from the standard FreeRTOS heap. The application writer must provide - * implementations for pvPortMallocStack() and vPortFreeStack() if set to 1. - * Defaults to 0 if left undefined. */ #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 - -/* Set configENABLE_HEAP_PROTECTOR to 1 to enable bounds checking and obfuscation - * to internal heap block pointers in heap_4.c and heap_5.c to help catch pointer - * corruptions. Defaults to 0 if left undefined. */ #define configENABLE_HEAP_PROTECTOR 0 -/******************************************************************************/ -/* Interrupt nesting behaviour configuration. *********************************/ -/******************************************************************************/ - -/* configKERNEL_INTERRUPT_PRIORITY sets the priority of the tick and context - * switch performing interrupts. Not supported by all FreeRTOS ports. See - * https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific to - * ARM Cortex-M devices. */ #define configKERNEL_INTERRUPT_PRIORITY 0 - -/* configMAX_SYSCALL_INTERRUPT_PRIORITY sets the interrupt priority above which - * FreeRTOS API calls must not be made. Interrupts above this priority are never - * disabled, so never delayed by RTOS activity. The default value is set to the - * highest interrupt priority (0). Not supported by all FreeRTOS ports. - * See https://www.freertos.org/RTOS-Cortex-M3-M4.html for information specific to - * ARM Cortex-M devices. */ #define configMAX_SYSCALL_INTERRUPT_PRIORITY 0 - -/* Another name for configMAX_SYSCALL_INTERRUPT_PRIORITY - the name used depends - * on the FreeRTOS port. */ #define configMAX_API_CALL_INTERRUPT_PRIORITY 0 -/******************************************************************************/ -/* Hook and callback function related definitions. ****************************/ -/******************************************************************************/ - -/* Set the following configUSE_* constants to 1 to include the named hook - * functionality in the build. Set to 0 to exclude the hook functionality from the - * build. The application writer is responsible for providing the hook function - * for any set to 1. See https://www.freertos.org/a00016.html. */ #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 - -/* Set configUSE_SB_COMPLETED_CALLBACK to 1 to have send and receive completed - * callbacks for each instance of a stream buffer or message buffer. When the - * option is set to 1, APIs xStreamBufferCreateWithCallback() and - * xStreamBufferCreateStaticWithCallback() (and likewise APIs for message - * buffer) can be used to create a stream buffer or message buffer instance - * with application provided callbacks. Defaults to 0 if left undefined. */ #define configUSE_SB_COMPLETED_CALLBACK 0 - -/* Set configCHECK_FOR_STACK_OVERFLOW to 1 or 2 for FreeRTOS to check for a - * stack overflow at the time of a context switch. Set to 0 to not look for a - * stack overflow. If configCHECK_FOR_STACK_OVERFLOW is 1 then the check only - * looks for the stack pointer being out of bounds when a task's context is saved - * to its stack - this is fast but somewhat ineffective. If - * configCHECK_FOR_STACK_OVERFLOW is 2 then the check looks for a pattern written - * to the end of a task's stack having been overwritten. This is slower, but will - * catch most (but not all) stack overflows. The application writer must provide - * the stack overflow callback when configCHECK_FOR_STACK_OVERFLOW is set to 1. - * See https://www.freertos.org/Stacks-and-stack-overflow-checking.html Defaults - * to 0 if left undefined. */ #define configCHECK_FOR_STACK_OVERFLOW 0 -/******************************************************************************/ -/* Run time and task stats gathering related definitions. *********************/ -/******************************************************************************/ - -/* Set configGENERATE_RUN_TIME_STATS to 1 to have FreeRTOS collect data on the - * processing time used by each task. Set to 0 to not collect the data. The - * application writer needs to provide a clock source if set to 1. Defaults to 0 - * if left undefined. See https://www.freertos.org/rtos-run-time-stats.html. */ #define configGENERATE_RUN_TIME_STATS 0 - -/* Set configUSE_TRACE_FACILITY to include additional task structure members - * are used by trace and visualisation functions and tools. Set to 0 to exclude - * the additional information from the structures. Defaults to 0 if left - * undefined. */ #define configUSE_TRACE_FACILITY 0 - -/* Set to 1 to include the vTaskList() and vTaskGetRunTimeStats() functions in - * the build. Set to 0 to exclude these functions from the build. These two - * functions introduce a dependency on string formatting functions that would - * otherwise not exist - hence they are kept separate. Defaults to 0 if left - * undefined. */ #define configUSE_STATS_FORMATTING_FUNCTIONS 0 - -/******************************************************************************/ -/* Co-routine related definitions. ********************************************/ -/******************************************************************************/ - -/* Set configUSE_CO_ROUTINES to 1 to include co-routine functionality in the - * build, or 0 to omit co-routine functionality from the build. To include - * co-routines, croutine.c must be included in the project. Defaults to 0 if left - * undefined. */ #define configUSE_CO_ROUTINES 0 - -/* configMAX_CO_ROUTINE_PRIORITIES defines the number of priorities available - * to the application co-routines. Any number of co-routines can share the same - * priority. Defaults to 0 if left undefined. */ #define configMAX_CO_ROUTINE_PRIORITIES 1 -/******************************************************************************/ -/* Debugging assistance. ******************************************************/ -/******************************************************************************/ - -/* configASSERT() has the same semantics as the standard C assert(). It can - * either be defined to take an action when the assertion fails, or not defined - * at all (i.e. comment out or delete the definitions) to completely remove - * assertions. configASSERT() can be defined to anything you want, for example - * you can call a function if an assert fails that passes the filename and line - * number of the failing assert (for example, "vAssertCalled( __FILE__, __LINE__ )" - * or it can simple disable interrupts and sit in a loop to halt all execution - * on the failing line for viewing in a debugger. */ #define configASSERT( x ) \ if( ( x ) == 0 ) \ { \ @@ -399,12 +66,6 @@ ; \ } -/******************************************************************************/ -/* Definitions that include or exclude functionality. *************************/ -/******************************************************************************/ - -/* Set the following configUSE_* constants to 1 to include the named feature in - * the build, or 0 to exclude the named feature from the build. */ #define configUSE_TASK_NOTIFICATIONS 1 #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 0 @@ -412,9 +73,6 @@ #define configUSE_QUEUE_SETS 0 #define configUSE_APPLICATION_TASK_TAG 0 -/* Set the following INCLUDE_* constants to 1 to incldue the named API function, - * or 0 to exclude the named API function. Most linkers will remove unused - * functions even when the constant is 1. */ #define INCLUDE_vTaskPrioritySet 0 #define INCLUDE_uxTaskPriorityGet 0 #define INCLUDE_vTaskDelete 0 From 811108b2238e943eccd41ce69d21924a9dd6ea64 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 12:08:30 +0000 Subject: [PATCH 51/88] fix hint --- crush.core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crush.core b/crush.core index d46f67d..512d881 100644 --- a/crush.core +++ b/crush.core @@ -256,7 +256,7 @@ scripts: iceprog_bitstream_hint: cmd: - echo - - "Run 'iceprog -o 0x20000 freertos/app/build/crush_freertos.bin' to load firmware to flash." + - "Run 'iceprog ...' in the build folder to program the board." iceprog_app_hint: cmd: - echo From 90c4bd8923672292c8ff26ff55f2c56f1970221c Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 12:08:52 +0000 Subject: [PATCH 52/88] remove unused file --- rtl/soc/flash.v | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 rtl/soc/flash.v diff --git a/rtl/soc/flash.v b/rtl/soc/flash.v deleted file mode 100644 index 13e61e6..0000000 --- a/rtl/soc/flash.v +++ /dev/null @@ -1,27 +0,0 @@ -`default_nettype none - -/* 32-bit * 16K word (64KByte) memory */ -module flash #( - parameter integer BASE_ADDRESS = 0 -) ( - input wire clk_i, - input wire rst_i, - input wire stb_i, - input wire cyc_i, - input wire [31:0] adr_i, - input wire [3:0] sel_i, - input wire [31:0] dat_i, - output wire [31:0] dat_o, - input wire we_i, - output reg ack_o, - output reg err_o, - output reg rty_o -); - - -// TODO: connect to the hard SPI controller -// Probably need a reset output signal that prevents the SoC booting while the -// SPI hardware is initialised. - - -endmodule From 28037a5df06d58f3d557f7bb1dc7c2d98659cd43 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 12:09:50 +0000 Subject: [PATCH 53/88] remove commented code --- rtl/soc/spi.v | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/rtl/soc/spi.v b/rtl/soc/spi.v index 9d864d7..d1f63f1 100644 --- a/rtl/soc/spi.v +++ b/rtl/soc/spi.v @@ -55,16 +55,4 @@ module spi #( assign err_o = 0; assign rty_o = 0; -/* - SB_IO #( - .PIN_TYPE(6'b101001), - .PULLUP(1'b1) - ) io[2:0] ( - .PACKAGE_PIN ({flash_mosi, flash_miso, flash_clk }), - .OUTPUT_ENABLE({spi_moe, spi_soe, spi_sckoe}), - .D_OUT_0 ({spi_mo, spi_so, spi_scko }), - .D_IN_0 ({spi_si, spi_mi, spi_scki }) - ); -*/ - endmodule From c824899185d837e45ca5d04725add86fb01d79e5 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 12:25:40 +0000 Subject: [PATCH 54/88] add new simulations to CI --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1f27bbc..4fee574 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,8 +16,9 @@ jobs: - sim_alu - sim_csr - sim_load_store - - sim_top - sim_mtimer + - sim_top + - sim_top_freertos # sim_cpu is not a testbench, but a target for RISCOF testing, so it # is not included here steps: From 04f363be1ae620b69c4e1d293f8ef09b0e2a103a Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 12:52:37 +0000 Subject: [PATCH 55/88] WIP set up build option to include machine mode --- .github/workflows/main.yml | 5 ++++- crush.core | 6 ++++++ rtl/cpu/alu.v | 2 ++ rtl/cpu/cpu.v | 33 ++++++++++++++++++++++++++++----- rtl/soc/spi.v | 1 - 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4fee574..df097b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -86,6 +86,9 @@ jobs: runs-on: ubuntu-22.04 container: image: barabas5532/crush-ci:4 + strategy: + matrix: + target: [crush, crush_machine] steps: - uses: actions/checkout@v4 with: @@ -103,7 +106,7 @@ jobs: timeout-minutes: 1 run: | . script/init.sh - fusesoc --verbose run crush + fusesoc --verbose run --target ${{ matrix.target }} firmware: runs-on: ubuntu-22.04 container: diff --git a/crush.core b/crush.core index 512d881..b7d340d 100644 --- a/crush.core +++ b/crush.core @@ -252,6 +252,12 @@ targets: toplevel: top_freertos_tb default_tool: icarus +parameters: + MACHINE_MODE: + datatype : bool + description: Enables machine privilege mode features + paramtype : vlogdefine + scripts: iceprog_bitstream_hint: cmd: diff --git a/rtl/cpu/alu.v b/rtl/cpu/alu.v index 9a72b8e..1ed55f0 100644 --- a/rtl/cpu/alu.v +++ b/rtl/cpu/alu.v @@ -80,6 +80,7 @@ module alu ( OPCODE_STORE: out = op_a + S_immediate; OPCODE_JAL: out = pc + J_immediate; OPCODE_JALR: out = (op_a + I_immediate) & ~1; +`ifdef MACHINE_MODE OPCODE_SYSTEM: case(funct3) FUNCT3_CSRRW: out = op_a; FUNCT3_CSRRWI: out = CSR_immediate; @@ -88,6 +89,7 @@ module alu ( FUNCT3_CSRRS: out = op_a | op_b; FUNCT3_CSRRSI: out = op_a | CSR_immediate; endcase +`endif default: ; endcase end diff --git a/rtl/cpu/cpu.v b/rtl/cpu/cpu.v index 611f0ed..0e1ce8c 100644 --- a/rtl/cpu/cpu.v +++ b/rtl/cpu/cpu.v @@ -15,9 +15,12 @@ module cpu #( output reg cyc_o, output reg[31:0] adr_o, output reg[3:0] sel_o, - output reg we_o, + output reg we_o +`ifdef MACHINE_MODE + , input wire timer_interrupt, input wire external_interrupt +`endif ); `include "params.vh" @@ -36,14 +39,15 @@ reg[31:0] read_data; wire [6:0] opcode = instruction[6:0]; wire [2:0] funct3 = instruction[14:12]; -wire instruction_is_ecall = instruction == {{12'b0}, {5'b0}, {FUNCT3_PRIV}, {5'b0}, {OPCODE_SYSTEM}}; - reg pc_load; reg pc_count; reg[31:0] pc_value; wire[31:0] pc; wire[31:0] pc_inc; +`ifdef MACHINE_MODE +wire instruction_is_ecall = instruction == {{12'b0}, {5'b0}, {FUNCT3_PRIV}, {5'b0}, {OPCODE_SYSTEM}}; + reg trap_taken; reg [31:0] mcause_; @@ -62,6 +66,7 @@ wire mie_meie = mie[11]; wire timer_interrupt_enable = mstatus_mie && mie_mtie; wire external_interrupt_enable = mstatus_mie && mie_meie; +`endif program_counter #(.INITIAL_PC(INITIAL_PC)) program_counter( .reset(rst_i), @@ -154,10 +159,12 @@ always @(posedge(clk_i)) begin if(rst_i) begin state <= STATE_RESET; instruction <= 32'hxxxx_xxxx; +`ifdef MACHINE_MODE mcause <= 0; mepc <= 0; mie <= 0; mstatus <= 0; +`endif end else begin case(state) STATE_FETCH: @@ -167,7 +174,7 @@ always @(posedge(clk_i)) begin end STATE_REG_READ: begin state <= STATE_EXECUTE; - +`ifdef MACHINE_MODE if(opcode == OPCODE_SYSTEM && funct3 != FUNCT3_PRIV) begin case(csr_address) CSR_MSTATUS: csr_read_value <= mstatus; @@ -177,7 +184,7 @@ always @(posedge(clk_i)) begin default: ; endcase end - +`endif end STATE_EXECUTE: begin state <= STATE_MEMORY; @@ -190,6 +197,7 @@ always @(posedge(clk_i)) begin read_data <= dat_i; end else state_change <= 0; +`ifdef MACHINE_MODE if(trap_taken) begin mcause <= mcause_; mepc <= pc; @@ -200,10 +208,12 @@ always @(posedge(clk_i)) begin // MPIE mstatus[7] <= 1; end +`endif end STATE_REG_WRITE: begin state <= STATE_FETCH; +`ifdef MACHINE_MODE if(opcode == OPCODE_SYSTEM) begin if(w_address == 0 && funct3 == FUNCT3_PRIV && @@ -222,6 +232,7 @@ always @(posedge(clk_i)) begin default: ; endcase end +`endif end default: state <= STATE_FETCH; endcase @@ -239,6 +250,7 @@ always @(*) begin OPCODE_JAL, OPCODE_JALR, OPCODE_LOAD: reg_w_en = 1; +`ifdef MACHINE_MODE OPCODE_SYSTEM: case(funct3) FUNCT3_CSRRW, @@ -249,6 +261,7 @@ always @(*) begin FUNCT3_CSRRSI: reg_w_en = 1; default: reg_w_en = 0; endcase +`endif default: reg_w_en = 0; endcase end @@ -276,8 +289,10 @@ always @(*) begin pc_load = 0; pc_value = 32'hxxxx_xxxx; +`ifdef MACHINE_MODE trap_taken = 0; mcause_ = 32'hxxxx_xxxx; +`endif stb_o = 0; cyc_o = 0; @@ -306,10 +321,12 @@ always @(*) begin alu_op_a = r_out1; alu_op_b = r_out2; +`ifdef MACHINE_MODE if((opcode == OPCODE_SYSTEM) && (funct3 != FUNCT3_CSRRW)) begin alu_op_a = csr_read_value; alu_op_b = r_out1; end +`endif end STATE_MEMORY: begin if(mem_r_en) begin @@ -339,6 +356,7 @@ always @(*) begin endcase end +`ifdef MACHINE_MODE if((timer_interrupt && timer_interrupt_enable) || (external_interrupt && external_interrupt_enable) || instruction_is_ecall) begin @@ -368,6 +386,7 @@ always @(*) begin mcause_ = {1'b1, 31'd11}; end end +`endif end STATE_REG_WRITE: begin w_enable = reg_w_en; @@ -387,7 +406,9 @@ always @(*) begin OPCODE_JALR: begin w_data = pc_inc; end +`ifdef MACHINE_MODE OPCODE_SYSTEM: w_data = csr_read_value; +`endif default: w_data = alu_out_r; endcase @@ -421,6 +442,7 @@ always @(*) begin end endcase +`ifdef MACHINE_MODE if(opcode == OPCODE_SYSTEM && w_address == 0 && funct3 == FUNCT3_PRIV && @@ -429,6 +451,7 @@ always @(*) begin pc_load = 1; pc_value = mepc; end +`endif end default: ; endcase diff --git a/rtl/soc/spi.v b/rtl/soc/spi.v index d1f63f1..1864e87 100644 --- a/rtl/soc/spi.v +++ b/rtl/soc/spi.v @@ -4,7 +4,6 @@ module spi #( parameter integer BASE_ADDRESS ) ( input wire clk_i, - // The memory we are trying to infer can not be reset // verilator lint_off UNUSEDSIGNAL input wire rst_i, // verilator lint_on UNUSEDSIGNAL From 852a5b59da92e71f75ece5dee7c624ed3b545bba Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 23 Jan 2025 13:07:54 +0000 Subject: [PATCH 56/88] WIP --- crush.core | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crush.core b/crush.core index b7d340d..d4ff2d8 100644 --- a/crush.core +++ b/crush.core @@ -147,6 +147,10 @@ targets: toplevel: top_freertos hooks: post_run: [iceprog_app_hint] + tools_append: + icestorm: + yosys_synth_options: + - "-DMACHINE_MODE" lint: default_tool : verilator @@ -226,6 +230,10 @@ targets: - sim_cpu_freertos toplevel: cpu_freertos_tb default_tool: icarus + tools_append: + icarus: + iverilog_options: + - "-DMACHINE_MODE" sim_mtimer: <<: *default @@ -251,6 +259,10 @@ targets: - top_freertos toplevel: top_freertos_tb default_tool: icarus + tools_append: + icarus: + iverilog_options: + - "-DMACHINE_MODE" parameters: MACHINE_MODE: From b86226d1829f1f497962affb8fa0d9ddec8b81cb Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 12:39:04 +0000 Subject: [PATCH 57/88] fix --- .github/workflows/main.yml | 2 +- crush_example/crush_example.core | 21 +--- crush_example/rtl/memory.v | 49 -------- crush_example/sim/memory_tb.v | 109 ------------------ .../crush_example_freertos.core | 26 +++-- 5 files changed, 20 insertions(+), 187 deletions(-) delete mode 100644 crush_example/rtl/memory.v delete mode 100644 crush_example/sim/memory_tb.v diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 54f8bba..0a3efda 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,7 +44,7 @@ jobs: image: barabas5532/crush-ci:4 strategy: matrix: - project: [crush, crush_example] + project: [crush, crush_example, crush_example_freertos] steps: - uses: actions/checkout@v4 with: diff --git a/crush_example/crush_example.core b/crush_example/crush_example.core index 45e83a8..60eee4d 100644 --- a/crush_example/crush_example.core +++ b/crush_example/crush_example.core @@ -9,8 +9,6 @@ filesets: - fw/binary/crush-blinky.data: file_type: user copyto: fw.data - - rtl/memory.v - - rtl/memory_ice40_spram.v - rtl/top.v - rtl/gpio.v file_type: verilogSource @@ -28,12 +26,6 @@ filesets: file_type: verilogSource depend: [crush_support] - sim_memory: - files: - - sim/memory_tb.v - file_type: systemVerilogSource - depend: [crush] - sim_top: files: - sim/top_tb.v @@ -71,7 +63,6 @@ targets: - verilator_waiver - rtl - sim_top - - sim_memory - sim_common tools: verilator: @@ -82,14 +73,6 @@ targets: - "-DNO_ICE40_DEFAULT_ASSIGNMENTS" toplevel: top_tb - sim_memory: - <<: *default - filesets_append: - - sim_common - - sim_memory - toplevel: memory_tb - default_tool: icarus - sim_top: <<: *default filesets_append: @@ -97,6 +80,10 @@ targets: toplevel: top_tb default_tool: icarus +parameters: + crush: + MACHINE_MODE: false + scripts: iceprog_hint: cmd: diff --git a/crush_example/rtl/memory.v b/crush_example/rtl/memory.v deleted file mode 100644 index 8fe9057..0000000 --- a/crush_example/rtl/memory.v +++ /dev/null @@ -1,49 +0,0 @@ -`default_nettype none - -module memory #( - parameter integer BASE_ADDRESS = 0 -) ( - input wire clk_i, - input wire rst_i, - input wire stb_i, - input wire cyc_i, - input wire [31:0] adr_i, - input wire [3:0] sel_i, - input wire [31:0] dat_i, - output reg [31:0] dat_o, - input wire we_i, - output reg ack_o, - output reg err_o, - output reg rty_o -); - localparam integer SIZE = 16384; - wire [31:0] memory_address = (adr_i - BASE_ADDRESS); - wire addressed = (adr_i >= BASE_ADDRESS) && (memory_address < SIZE); - wire [31:0] memory_data; - - memory_ice40_spram ram( - .clk(clk_i), - .rst(rst_i), - .wen(stb_i & cyc_i & we_i & addressed), - .wmask(sel_i), - .addr(memory_address[15:2]), - .wdata(dat_i), - .rdata(memory_data) - ); - - always @(*) begin - if (ack_o) dat_o = memory_data; - else dat_o = 32'hzzzz_zzzz; - end - - always @(posedge clk_i) begin - ack_o <= 0; - err_o <= 0; - rty_o <= 0; - - if (stb_i & cyc_i & !ack_o & addressed) begin - ack_o <= 1; - end - end - -endmodule diff --git a/crush_example/sim/memory_tb.v b/crush_example/sim/memory_tb.v deleted file mode 100644 index 2d5bc4b..0000000 --- a/crush_example/sim/memory_tb.v +++ /dev/null @@ -1,109 +0,0 @@ -`default_nettype none - -`timescale 1s/1ms - -`include "fatal_assert.vh" - -module memory_tb; - -reg clk = 1; -reg reset = 1; -reg stb_o = 0; -reg cyc_o = 0; -reg[31:0] adr_o; -reg[3:0] sel_o; -wire[31:0] dat_i; -reg[31:0] dat_o; -reg we_o; -wire ack_i; -wire err_i; -wire rty_i; - -memory #(.BASE_ADDRESS(0)) dut ( - .clk_i(clk), - .rst_i(reset), - .stb_i(stb_o), - .cyc_i(cyc_o), - .adr_i(adr_o), - .sel_i(sel_o), - .dat_i(dat_o), - .dat_o(dat_i), - .we_i(we_o), - .ack_o(ack_i), - .err_o(err_i), - .rty_o(rty_i) -); - -always begin - #0.5 clk = !clk; -end - -initial begin - $dumpfile("memory.vcd"); - $dumpvars; - - #0.1 - - #1 - reset = 1; - - #1 - reset = 0; - - #1 - // 32-bit write to 0 - // Based on Wishbone B4 3.2.3 Classic standard SINGLE WRITE Cycle - // Clock edge 0 - `fatal_assert(!ack_i); - - adr_o = 32'b0; - dat_o = 32'h01234567; - we_o = 1'b1; - sel_o = 4'b1111; - - cyc_o = 1; - stb_o = 1; - - #1 - // Clock edge 1 - `fatal_assert(ack_i); - - #1 - // Clock edge 2 - stb_o = 0; - cyc_o = 0; - #0 - `fatal_assert(!ack_i); - - adr_o = 32'hxxxxxxxx; - dat_o = 32'hxxxxxxxx; - sel_o = 4'hx; - we_o = 1'bx; - - #1 - // 32-bit read from 0 - // Based on Wishbone B4 3.2.1 Classic standard SINGLE READ Cycle - `fatal_assert(!ack_i); - adr_o = 0; - we_o = 0; - sel_o = 4'b1111; - cyc_o = 1; - stb_o = 1; - - // Clock edge 0 - #1 - `fatal_assert(ack_i); - `fatal_assert(dat_i == 32'h01234567); - - #1 - // Clock edge 2 - stb_o = 0; - cyc_o = 0; - #0 - `fatal_assert(!ack_i); - - #1 - $stop; -end - -endmodule diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 45e83a8..6e2f458 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -9,10 +9,10 @@ filesets: - fw/binary/crush-blinky.data: file_type: user copyto: fw.data - - rtl/memory.v - rtl/memory_ice40_spram.v + - rtl/memory_ice40_spram_wb.v + - rtl/spi.v - rtl/top.v - - rtl/gpio.v file_type: verilogSource depend: [crush] @@ -28,9 +28,9 @@ filesets: file_type: verilogSource depend: [crush_support] - sim_memory: + sim_cpu: files: - - sim/memory_tb.v + - sim/cpu_freertos_tb.v file_type: systemVerilogSource depend: [crush] @@ -50,7 +50,7 @@ targets: filesets: - rtl - pcf - toplevel: top + toplevel: top_freertos default_tool: icestorm tools: icestorm: @@ -71,7 +71,7 @@ targets: - verilator_waiver - rtl - sim_top - - sim_memory + - sim_cpu - sim_common tools: verilator: @@ -80,23 +80,27 @@ targets: - "-Wall -timing" # Disable default values in yosys's simulation modules. - "-DNO_ICE40_DEFAULT_ASSIGNMENTS" - toplevel: top_tb + toplevel: top_freertos_tb - sim_memory: + sim_cpu: <<: *default filesets_append: - sim_common - - sim_memory - toplevel: memory_tb + - sim_cpu + toplevel: cpu_freertos_tb default_tool: icarus sim_top: <<: *default filesets_append: - sim_top - toplevel: top_tb + toplevel: top_freertos_tb default_tool: icarus +parameters: + crush: + MACHINE_MODE: true + scripts: iceprog_hint: cmd: From c2f849b6843871bb94ae2130caefc6cd783cc6a2 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 12:46:14 +0000 Subject: [PATCH 58/88] fix ci --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0a3efda..b79de0f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ jobs: - sim_top uses: ./.github/workflows/simulate.yml with: - project: crush_example + project: crush_example_freertos target: ${{ matrix.target }} verilog-lint: runs-on: ubuntu-22.04 @@ -90,7 +90,7 @@ jobs: image: barabas5532/crush-ci:4 strategy: matrix: - target: [crush, crush_machine] + project: [crush_example, crush_example_freertos] steps: - uses: actions/checkout@v4 with: @@ -108,7 +108,7 @@ jobs: timeout-minutes: 1 run: | . script/init.sh - fusesoc --verbose run --target ${{ matrix.target }} + fusesoc --verbose run ${{ matrix.project }} firmware: runs-on: ubuntu-22.04 container: From 33f10b1c86b97adb9d2502d4be64e79c30b649fd Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 13:17:24 +0000 Subject: [PATCH 59/88] fix --- .github/workflows/main.yml | 1 - crush/crush.core | 24 +++++++++++++++++++ crush_example/crush_example.core | 4 ---- .../crush_example_freertos.core | 4 ---- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b79de0f..3911966 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,6 @@ jobs: strategy: matrix: target: - - sim_memory - sim_top uses: ./.github/workflows/simulate.yml with: diff --git a/crush/crush.core b/crush/crush.core index 9425cb2..74b7c8a 100644 --- a/crush/crush.core +++ b/crush/crush.core @@ -11,6 +11,7 @@ filesets: - rtl/inst_decode_registers.v - rtl/inst_immediate_decode.v - rtl/memory_infer.v: {file_type: systemVerilogSource} + - rtl/mtimer.v - rtl/params.vh: {is_include_file: true} - rtl/program_counter.v - rtl/registers.v @@ -40,6 +41,16 @@ filesets: - sim/cpu_tb.v file_type: systemVerilogSource + sim_csr: + files: + - sim/csr_tb.v + file_type: systemVerilogSource + + sim_mtimer: + files: + - sim/mtimer_tb.v + file_type: systemVerilogSource + verilator_waiver: files: - ../data/verilator_waiver.vlt @@ -102,3 +113,16 @@ targets: toplevel: cpu_tb default_tool: icarus + sim_csr: + <<: *default + filesets_append: + - sim_csr + toplevel: csr_tb + default_tool: icarus + + sim_mtimer: + <<: *default + filesets_append: + - sim_mtimer + toplevel: mtimer_tb + default_tool: icarus diff --git a/crush_example/crush_example.core b/crush_example/crush_example.core index 60eee4d..306669c 100644 --- a/crush_example/crush_example.core +++ b/crush_example/crush_example.core @@ -80,10 +80,6 @@ targets: toplevel: top_tb default_tool: icarus -parameters: - crush: - MACHINE_MODE: false - scripts: iceprog_hint: cmd: diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 6e2f458..7e64044 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -97,10 +97,6 @@ targets: toplevel: top_freertos_tb default_tool: icarus -parameters: - crush: - MACHINE_MODE: true - scripts: iceprog_hint: cmd: From 8730e972c25d5e0fe966ddb8bdebb2aa2799f6fb Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 13:18:22 +0000 Subject: [PATCH 60/88] fix --- crush_example_freertos/crush_example_freertos.core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 7e64044..2174c50 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -1,7 +1,7 @@ CAPI=2: # vim:syntax=yaml: -name: ::crush_example:0.0.1 +name: ::crush_example_freertos:0.0.1 filesets: rtl: From 11f4da33fb6c757a99578f858a7986c192523bf3 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 13:32:39 +0000 Subject: [PATCH 61/88] fix fw for freertos demo --- .../fw}/app/CMakeLists.txt | 4 +- .../fw}/app/TC-crush.cmake | 0 .../fw/app/binary/crush_freertos.bin | Bin 0 -> 17608 bytes .../fw/app/binary/crush_freertos.data | 1103 +++++++++++++++++ .../fw}/app/crush.ld | 0 .../fw}/app/freertos_config/CMakeLists.txt | 0 .../freertos_config/include/FreeRTOSConfig.h | 0 .../fw}/app/freertos_config/include/stdint.h | 0 .../fw}/app/freertos_config/include/stdlib.h | 0 .../fw}/app/freertos_config/include/string.h | 0 .../fw}/app/freertos_config/string.c | 0 .../fw}/app/src/hal.c | 0 .../fw}/app/src/hal.h | 0 .../fw}/app/src/main.c | 0 .../fw}/app/src/start.S | 0 .../fw}/app/src/start.c | 0 .../fw/spi_bootloader}/CMakeLists.txt | 2 +- .../fw/spi_bootloader}/TC-crush.cmake | 0 .../fw/spi_bootloader/binary/crush-boot.data | 9 + .../fw/spi_bootloader}/boot.S | 0 .../fw/spi_bootloader}/crush-boot.ld | 0 21 files changed, 1115 insertions(+), 3 deletions(-) rename {freertos => crush_example_freertos/fw}/app/CMakeLists.txt (91%) rename {freertos => crush_example_freertos/fw}/app/TC-crush.cmake (100%) create mode 100755 crush_example_freertos/fw/app/binary/crush_freertos.bin create mode 100755 crush_example_freertos/fw/app/binary/crush_freertos.data rename {freertos => crush_example_freertos/fw}/app/crush.ld (100%) rename {freertos => crush_example_freertos/fw}/app/freertos_config/CMakeLists.txt (100%) rename {freertos => crush_example_freertos/fw}/app/freertos_config/include/FreeRTOSConfig.h (100%) rename {freertos => crush_example_freertos/fw}/app/freertos_config/include/stdint.h (100%) rename {freertos => crush_example_freertos/fw}/app/freertos_config/include/stdlib.h (100%) rename {freertos => crush_example_freertos/fw}/app/freertos_config/include/string.h (100%) rename {freertos => crush_example_freertos/fw}/app/freertos_config/string.c (100%) rename {freertos => crush_example_freertos/fw}/app/src/hal.c (100%) rename {freertos => crush_example_freertos/fw}/app/src/hal.h (100%) rename {freertos => crush_example_freertos/fw}/app/src/main.c (100%) rename {freertos => crush_example_freertos/fw}/app/src/start.S (100%) rename {freertos => crush_example_freertos/fw}/app/src/start.c (100%) rename {boot_fw => crush_example_freertos/fw/spi_bootloader}/CMakeLists.txt (90%) rename {boot_fw => crush_example_freertos/fw/spi_bootloader}/TC-crush.cmake (100%) create mode 100755 crush_example_freertos/fw/spi_bootloader/binary/crush-boot.data rename {boot_fw => crush_example_freertos/fw/spi_bootloader}/boot.S (100%) rename {boot_fw => crush_example_freertos/fw/spi_bootloader}/crush-boot.ld (100%) diff --git a/freertos/app/CMakeLists.txt b/crush_example_freertos/fw/app/CMakeLists.txt similarity index 91% rename from freertos/app/CMakeLists.txt rename to crush_example_freertos/fw/app/CMakeLists.txt index 05b6f05..690a119 100644 --- a/freertos/app/CMakeLists.txt +++ b/crush_example_freertos/fw/app/CMakeLists.txt @@ -49,13 +49,13 @@ target_link_libraries(${PROJECT_NAME} PRIVATE gcc) string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) find_program(objcopy_program ${objcopy_name} REQUIRED) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${objcopy_program} -O binary -j .text -j .data -j .bss -j .stack ${PROJECT_NAME} ${PROJECT_NAME}.bin + COMMAND ${objcopy_program} -O binary -j .text -j .data -j .bss -j .stack ${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/binary/${PROJECT_NAME}.bin WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) # Output is loaded to flash at offset 0x20_000. the adjust-vma makes sure it # will be loaded into the simulation at the correct address. add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${objcopy_program} -O verilog --adjust-vma -0x0ffe0000 --verilog-data-width 1 ${PROJECT_NAME} ${PROJECT_NAME}.data + COMMAND ${objcopy_program} -O verilog --adjust-vma -0x0ffe0000 --verilog-data-width 1 ${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/binary/${PROJECT_NAME}.data WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/freertos/app/TC-crush.cmake b/crush_example_freertos/fw/app/TC-crush.cmake similarity index 100% rename from freertos/app/TC-crush.cmake rename to crush_example_freertos/fw/app/TC-crush.cmake diff --git a/crush_example_freertos/fw/app/binary/crush_freertos.bin b/crush_example_freertos/fw/app/binary/crush_freertos.bin new file mode 100755 index 0000000000000000000000000000000000000000..230ba8c566f1550032e70a4725756db08ddc7185 GIT binary patch literal 17608 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 Date: Fri, 24 Jan 2025 13:36:21 +0000 Subject: [PATCH 62/88] Udpate core file --- crush_example_freertos/crush_example_freertos.core | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 2174c50..39cc3c8 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -6,9 +6,9 @@ name: ::crush_example_freertos:0.0.1 filesets: rtl: files: - - fw/binary/crush-blinky.data: + - fw/spi_bootloader/binary/crush-boot.data: file_type: user - copyto: fw.data + copyto: boot.data - rtl/memory_ice40_spram.v - rtl/memory_ice40_spram_wb.v - rtl/spi.v @@ -37,6 +37,9 @@ filesets: sim_top: files: - sim/top_tb.v + - fw/app/binary/crush_freertos.data: + file_type: user + copyto: crush_freertos.data file_type: systemVerilogSource depend: [crush] From e08dfa4d99e2a3080f55915688a526b6be5e6b48 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 14:50:55 +0000 Subject: [PATCH 63/88] fix machine mode parameter --- crush/crush.core | 10 ++++++++++ crush/sim/csr_tb.v | 4 ++-- crush_example/crush_example.core | 2 ++ crush_example_freertos/crush_example_freertos.core | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/crush/crush.core b/crush/crush.core index 74b7c8a..39037d7 100644 --- a/crush/crush.core +++ b/crush/crush.core @@ -45,11 +45,13 @@ filesets: files: - sim/csr_tb.v file_type: systemVerilogSource + depend: [crush_support] sim_mtimer: files: - sim/mtimer_tb.v file_type: systemVerilogSource + depend: [crush_support] verilator_waiver: files: @@ -119,6 +121,8 @@ targets: - sim_csr toplevel: csr_tb default_tool: icarus + parameters: + - MACHINE_MODE=true sim_mtimer: <<: *default @@ -126,3 +130,9 @@ targets: - sim_mtimer toplevel: mtimer_tb default_tool: icarus + +parameters: + MACHINE_MODE: + datatype : bool + description: Enables machine privilege mode features + paramtype : vlogdefine diff --git a/crush/sim/csr_tb.v b/crush/sim/csr_tb.v index 7c55fa3..ca99458 100644 --- a/crush/sim/csr_tb.v +++ b/crush/sim/csr_tb.v @@ -34,7 +34,7 @@ string test_case_name = ""; reg flash_ack_o = 0; reg[31:0] flash_dat_o = 32'hzzzz_zzzz; -cpu #(.INITIAL_PC('h1000_0000)) cpu ( +crush_cpu #(.INITIAL_PC('h1000_0000)) cpu ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), @@ -50,7 +50,7 @@ cpu #(.INITIAL_PC('h1000_0000)) cpu ( ); wire memory_ack_o; -sim_memory #(.BASE_ADDRESS('h2000_0000), .SIZE('h4000)) memory ( +memory_infer #(.BASE_ADDRESS('h2000_0000), .SIZE('h4000)) memory ( .clk_i(clk), .rst_i(reset), .stb_i(stb_o), diff --git a/crush_example/crush_example.core b/crush_example/crush_example.core index 306669c..3238370 100644 --- a/crush_example/crush_example.core +++ b/crush_example/crush_example.core @@ -56,6 +56,8 @@ targets: - "-gassertions" hooks: post_run: [iceprog_hint] + parameters: + - MACHINE_MODE=false lint: default_tool : verilator diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 39cc3c8..5261aa8 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -67,6 +67,8 @@ targets: - "-gassertions" hooks: post_run: [iceprog_hint] + parameters: + - MACHINE_MODE=true lint: default_tool : verilator From c4f90be2a91282f17573f0a0e6fb6b4937776453 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 15:52:53 +0000 Subject: [PATCH 64/88] fix --- .github/workflows/main.yml | 1 + crush/crush.core | 2 ++ crush_example/crush_example.core | 2 ++ crush_example_freertos/crush_example_freertos.core | 4 ++++ 4 files changed, 9 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3911966..8dcc099 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -33,6 +33,7 @@ jobs: matrix: target: - sim_top + - sim_cpu uses: ./.github/workflows/simulate.yml with: project: crush_example_freertos diff --git a/crush/crush.core b/crush/crush.core index 39037d7..a45d026 100644 --- a/crush/crush.core +++ b/crush/crush.core @@ -130,6 +130,8 @@ targets: - sim_mtimer toplevel: mtimer_tb default_tool: icarus + parameters: + - MACHINE_MODE=true parameters: MACHINE_MODE: diff --git a/crush_example/crush_example.core b/crush_example/crush_example.core index 3238370..cdc5d70 100644 --- a/crush_example/crush_example.core +++ b/crush_example/crush_example.core @@ -81,6 +81,8 @@ targets: - sim_top toplevel: top_tb default_tool: icarus + parameters: + - MACHINE_MODE=false scripts: iceprog_hint: diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 5261aa8..9c2b143 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -94,6 +94,8 @@ targets: - sim_cpu toplevel: cpu_freertos_tb default_tool: icarus + parameters: + - MACHINE_MODE=true sim_top: <<: *default @@ -101,6 +103,8 @@ targets: - sim_top toplevel: top_freertos_tb default_tool: icarus + parameters: + - MACHINE_MODE=true scripts: iceprog_hint: From b46ae1387ec5c5cdc5bd06046e4a8ee8611de3cd Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 15:59:07 +0000 Subject: [PATCH 65/88] remove file left by mistake --- simulate.yml | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 simulate.yml diff --git a/simulate.yml b/simulate.yml deleted file mode 100644 index dc2f19f..0000000 --- a/simulate.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Simulate - -on: - workflow_call: - inputs: - project: - required: true - type: string - target: - required: true - type: string - -jobs: - simulate: - runs-on: ubuntu-22.04 - container: - image: barabas5532/crush-ci:4 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Set up python environment - run: | - python -m venv .venv - . .venv/bin/activate - python -m pip install -r requirements.txt - # Every step runs in its own shell. Activating the venv really just - # modifies the path. Persist the modified path, so that other steps - # also use the venv. - echo PATH=$PATH >> $GITHUB_ENV - - name: Run simulation - timeout-minutes: 1 - run: | - . script/init.sh - fusesoc run --target ${{ inputs.target }} --resolve-env-vars-early ${{ inputs.project }} From 581528ab1a9721aaee7a7bc07675b1c36df7cf4f Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 16:00:42 +0000 Subject: [PATCH 66/88] fix mtimer test --- crush/sim/mtimer_tb.v | 3 --- 1 file changed, 3 deletions(-) diff --git a/crush/sim/mtimer_tb.v b/crush/sim/mtimer_tb.v index 583e965..13dbbfb 100644 --- a/crush/sim/mtimer_tb.v +++ b/crush/sim/mtimer_tb.v @@ -21,7 +21,6 @@ wire err_i; wire rty_i; wire interrupt; -reg interrupt_enable = 0; localparam BASE_ADDRESS = 32'h100; @@ -39,7 +38,6 @@ mtimer #(.BASE_ADDRESS(BASE_ADDRESS)) dut ( .ack_o(ack_i), .err_o(err_i), .rty_o(rty_i), - .interrupt_enable(interrupt_enable), .interrupt(interrupt) ); @@ -122,7 +120,6 @@ initial begin // Set mtimecmp to a very large value to ensure interrupt doesn't trigger // immediately write_register(BASE_ADDRESS + 12, 1); - #0 interrupt_enable = 1; #0 `fatal_assert(!interrupt); // mtime = 1000 write_register(BASE_ADDRESS + 0, 1000); From 7794112b9d3a293942ad823927efc11040ca3cdb Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 16:01:36 +0000 Subject: [PATCH 67/88] remove unnesessary parameter --- crush/crush.core | 2 -- 1 file changed, 2 deletions(-) diff --git a/crush/crush.core b/crush/crush.core index a45d026..39037d7 100644 --- a/crush/crush.core +++ b/crush/crush.core @@ -130,8 +130,6 @@ targets: - sim_mtimer toplevel: mtimer_tb default_tool: icarus - parameters: - - MACHINE_MODE=true parameters: MACHINE_MODE: From c970b8fa1769326eddd39b65626f4e6d3539f609 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 16:07:02 +0000 Subject: [PATCH 68/88] fix MACHINE_MODE parameter not exported --- crush/crush.core | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crush/crush.core b/crush/crush.core index 39037d7..a0d4d5e 100644 --- a/crush/crush.core +++ b/crush/crush.core @@ -68,6 +68,8 @@ targets: iverilog_options: - "-g2012" - "-gassertions" + parameters: + - MACHINE_MODE lint: default_tool : verilator From f91ab82ff8527e00d7384dfc83e6e92897e22b8c Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 16:26:18 +0000 Subject: [PATCH 69/88] fix up build system --- crush/crush.core | 10 +-- crush_example/crush_example.core | 5 +- .../crush_example_freertos.core | 16 +++-- crush_example_freertos/data/icebreaker.pcf | 68 +++++++++++++++++++ .../rtl/{top_freertos.v => top.v} | 4 +- .../sim/{cpu_freertos_tb.v => cpu_tb.v} | 0 .../sim/{top_freertos_tb.v => top_tb.v} | 4 +- .../crush_testing.core | 6 +- .../sim/fatal_assert.vh | 0 crush_util/crush_util.core | 15 ++++ {crush_example => crush_util}/rtl/gpio.v | 0 run_sim.sh | 2 - script/init.sh | 4 +- 13 files changed, 107 insertions(+), 27 deletions(-) create mode 100644 crush_example_freertos/data/icebreaker.pcf rename crush_example_freertos/rtl/{top_freertos.v => top.v} (97%) rename crush_example_freertos/sim/{cpu_freertos_tb.v => cpu_tb.v} (100%) rename crush_example_freertos/sim/{top_freertos_tb.v => top_tb.v} (96%) rename support/crush_support.core => crush_testing/crush_testing.core (67%) rename {support => crush_testing}/sim/fatal_assert.vh (100%) create mode 100644 crush_util/crush_util.core rename {crush_example => crush_util}/rtl/gpio.v (100%) delete mode 100755 run_sim.sh diff --git a/crush/crush.core b/crush/crush.core index a0d4d5e..7e0d856 100644 --- a/crush/crush.core +++ b/crush/crush.core @@ -21,19 +21,19 @@ filesets: files: - sim/inst_immediate_decode_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] sim_alu: files: - sim/alu_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] sim_load_store: files: - sim/load_store_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] sim_cpu: files: @@ -45,13 +45,13 @@ filesets: files: - sim/csr_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] sim_mtimer: files: - sim/mtimer_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] verilator_waiver: files: diff --git a/crush_example/crush_example.core b/crush_example/crush_example.core index cdc5d70..36ec04a 100644 --- a/crush_example/crush_example.core +++ b/crush_example/crush_example.core @@ -10,9 +10,8 @@ filesets: file_type: user copyto: fw.data - rtl/top.v - - rtl/gpio.v file_type: verilogSource - depend: [crush] + depend: [crush, crush_util] pcf: files: @@ -24,7 +23,7 @@ filesets: # export YOSYS_DATDIR=$(yosys-config --datdir) - $YOSYS_DATDIR/ice40/cells_sim.v file_type: verilogSource - depend: [crush_support] + depend: [crush_testing] sim_top: files: diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 9c2b143..1627cea 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -14,7 +14,7 @@ filesets: - rtl/spi.v - rtl/top.v file_type: verilogSource - depend: [crush] + depend: [crush, crush_util, simple_spi] pcf: files: @@ -26,11 +26,11 @@ filesets: # export YOSYS_DATDIR=$(yosys-config --datdir) - $YOSYS_DATDIR/ice40/cells_sim.v file_type: verilogSource - depend: [crush_support] + depend: [crush_testing] sim_cpu: files: - - sim/cpu_freertos_tb.v + - sim/cpu_tb.v file_type: systemVerilogSource depend: [crush] @@ -40,6 +40,7 @@ filesets: - fw/app/binary/crush_freertos.data: file_type: user copyto: crush_freertos.data + - sim/s25fl128s.v file_type: systemVerilogSource depend: [crush] @@ -53,7 +54,7 @@ targets: filesets: - rtl - pcf - toplevel: top_freertos + toplevel: top default_tool: icestorm tools: icestorm: @@ -85,14 +86,14 @@ targets: - "-Wall -timing" # Disable default values in yosys's simulation modules. - "-DNO_ICE40_DEFAULT_ASSIGNMENTS" - toplevel: top_freertos_tb + toplevel: top_tb sim_cpu: <<: *default filesets_append: - sim_common - sim_cpu - toplevel: cpu_freertos_tb + toplevel: cpu_tb default_tool: icarus parameters: - MACHINE_MODE=true @@ -100,8 +101,9 @@ targets: sim_top: <<: *default filesets_append: + - sim_common - sim_top - toplevel: top_freertos_tb + toplevel: top_tb default_tool: icarus parameters: - MACHINE_MODE=true diff --git a/crush_example_freertos/data/icebreaker.pcf b/crush_example_freertos/data/icebreaker.pcf new file mode 100644 index 0000000..429bf54 --- /dev/null +++ b/crush_example_freertos/data/icebreaker.pcf @@ -0,0 +1,68 @@ +# 12 MHz clock +set_io -nowarn CLK 35 +set_frequency CLK 12 + +# RS232 +set_io -nowarn RX 6 +set_io -nowarn TX 9 + +# LEDs and Button +set_io -nowarn BTN_N 10 +set_io -nowarn LEDR_N 11 +set_io -nowarn LEDG_N 37 + +# RGB LED Driver +set_io -nowarn LED_RED_N 39 +set_io -nowarn LED_GRN_N 40 +set_io -nowarn LED_BLU_N 41 +set_io -nowarn LED_RGB[0] 39 +set_io -nowarn LED_RGB[1] 40 +set_io -nowarn LED_RGB[2] 41 + +# SPI Flash +set_io -nowarn FLASH_SCK 15 +set_io -nowarn FLASH_SSB 16 +set_io -nowarn FLASH_IO0 14 +set_io -nowarn FLASH_IO1 17 +set_io -nowarn FLASH_IO2 12 +set_io -nowarn FLASH_IO3 13 + +# PMOD 1A +set_io -nowarn P1A1 4 +set_io -nowarn P1A2 2 +set_io -nowarn P1A3 47 +set_io -nowarn P1A4 45 +set_io -nowarn P1A7 3 +set_io -nowarn P1A8 48 +set_io -nowarn P1A9 46 +set_io -nowarn P1A10 44 + +# PMOD 1B +set_io -nowarn P1B1 43 +set_io -nowarn P1B2 38 +set_io -nowarn P1B3 34 +set_io -nowarn P1B4 31 +set_io -nowarn P1B7 42 +set_io -nowarn P1B8 36 +set_io -nowarn P1B9 32 +set_io -nowarn P1B10 28 + +# PMOD 2 +set_io -nowarn P2_1 27 +set_io -nowarn P2_2 25 +set_io -nowarn P2_3 21 +set_io -nowarn P2_4 19 +set_io -nowarn P2_7 26 +set_io -nowarn P2_8 23 +set_io -nowarn P2_9 20 +set_io -nowarn P2_10 18 + +# LEDs and Buttons (PMOD 2) +set_io -nowarn LED1 26 +set_io -nowarn LED2 27 +set_io -nowarn LED3 25 +set_io -nowarn LED4 23 +set_io -nowarn LED5 21 +set_io -nowarn BTN1 20 +set_io -nowarn BTN2 19 +set_io -nowarn BTN3 18 diff --git a/crush_example_freertos/rtl/top_freertos.v b/crush_example_freertos/rtl/top.v similarity index 97% rename from crush_example_freertos/rtl/top_freertos.v rename to crush_example_freertos/rtl/top.v index 49bf4a3..1594822 100644 --- a/crush_example_freertos/rtl/top_freertos.v +++ b/crush_example_freertos/rtl/top.v @@ -1,6 +1,6 @@ `default_nettype none -module top_freertos ( +module top ( input wire CLK, input wire BTN_N, input wire BTN1, @@ -28,7 +28,7 @@ wire rty_i; wire timer_interrupt; -cpu #(.INITIAL_PC('h0000_0000), .TRAP_PC('h1000_0100)) cpu ( +crush_cpu #(.INITIAL_PC('h0000_0000), .TRAP_PC('h1000_0100)) cpu ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), diff --git a/crush_example_freertos/sim/cpu_freertos_tb.v b/crush_example_freertos/sim/cpu_tb.v similarity index 100% rename from crush_example_freertos/sim/cpu_freertos_tb.v rename to crush_example_freertos/sim/cpu_tb.v diff --git a/crush_example_freertos/sim/top_freertos_tb.v b/crush_example_freertos/sim/top_tb.v similarity index 96% rename from crush_example_freertos/sim/top_freertos_tb.v rename to crush_example_freertos/sim/top_tb.v index 3383ad8..edc499e 100644 --- a/crush_example_freertos/sim/top_freertos_tb.v +++ b/crush_example_freertos/sim/top_tb.v @@ -6,7 +6,7 @@ `timescale 1ns/1ps -module top_freertos_tb; +module top_tb; reg clk; reg btn_n; @@ -18,7 +18,7 @@ wire flash_ssb; wire flash_io0; wire flash_io1; -top_freertos dut( +top dut( .CLK(clk), .BTN_N(btn_n), .BTN1(btn1), diff --git a/support/crush_support.core b/crush_testing/crush_testing.core similarity index 67% rename from support/crush_support.core rename to crush_testing/crush_testing.core index 1d27d0f..261a2cc 100644 --- a/support/crush_support.core +++ b/crush_testing/crush_testing.core @@ -1,7 +1,7 @@ CAPI=2: # vim:syntax=yaml: -name: ::crush_support:0.0.1 +name: ::crush_testing:0.0.1 filesets: sim_common: @@ -14,7 +14,3 @@ targets: default: &default filesets: - sim_common - tools: - icarus: - iverilog_options: - - "-gassertions" diff --git a/support/sim/fatal_assert.vh b/crush_testing/sim/fatal_assert.vh similarity index 100% rename from support/sim/fatal_assert.vh rename to crush_testing/sim/fatal_assert.vh diff --git a/crush_util/crush_util.core b/crush_util/crush_util.core new file mode 100644 index 0000000..0e3cc20 --- /dev/null +++ b/crush_util/crush_util.core @@ -0,0 +1,15 @@ +CAPI=2: +# vim:syntax=yaml: + +name: ::crush_util:0.0.1 + +filesets: + rtl: + files: + - rtl/gpio.v + file_type: verilogSource + +targets: + default: &default + filesets: + - rtl diff --git a/crush_example/rtl/gpio.v b/crush_util/rtl/gpio.v similarity index 100% rename from crush_example/rtl/gpio.v rename to crush_util/rtl/gpio.v diff --git a/run_sim.sh b/run_sim.sh deleted file mode 100755 index 93f44e3..0000000 --- a/run_sim.sh +++ /dev/null @@ -1,2 +0,0 @@ -cmake --build ./freertos/app/build -fusesoc run --target sim_cpu_freertos --build --resolve-env-vars-early crush && vvp -n build/crush_0.0.1/sim_cpu_freertos-icarus/crush_0.0.1 +BINARY_PATH=freertos/app/build/crush_freertos.bin diff --git a/script/init.sh b/script/init.sh index af648f6..54b711e 100755 --- a/script/init.sh +++ b/script/init.sh @@ -2,9 +2,11 @@ export YOSYS_DATDIR=$(yosys-config --datdir) +rm -f fusesoc.conf rm -rf fusesoc_libraries fusesoc library add --sync-type local crush crush fusesoc library add --sync-type local crush_example crush_example fusesoc library add --sync-type local crush_example_freertos crush_example_freertos -fusesoc library add --sync-type local crush_support support +fusesoc library add --sync-type local crush_testing crush_testing +fusesoc library add --sync-type local crush_util crush_util fusesoc library add fusesoc_cores https://github.com/fusesoc/fusesoc-cores From dbc2f81451a193ee06ce2a4467f49c18bec35b4f Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 16:31:28 +0000 Subject: [PATCH 70/88] fix tb --- crush_example_freertos/sim/cpu_tb.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crush_example_freertos/sim/cpu_tb.v b/crush_example_freertos/sim/cpu_tb.v index 6c8ba0b..b6e47bb 100644 --- a/crush_example_freertos/sim/cpu_tb.v +++ b/crush_example_freertos/sim/cpu_tb.v @@ -11,7 +11,7 @@ `timescale 1ns/1ps -module cpu_freertos_tb; +module cpu_tb; `include "params.vh" From f7277257afbaf0370572d8e948e976acb8175bd7 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 16:33:17 +0000 Subject: [PATCH 71/88] fix spi --- crush_example_freertos/rtl/spi.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crush_example_freertos/rtl/spi.v b/crush_example_freertos/rtl/spi.v index 1864e87..b430413 100644 --- a/crush_example_freertos/rtl/spi.v +++ b/crush_example_freertos/rtl/spi.v @@ -1,7 +1,7 @@ `default_nettype none module spi #( - parameter integer BASE_ADDRESS + parameter integer BASE_ADDRESS=0 ) ( input wire clk_i, // verilator lint_off UNUSEDSIGNAL From 0c41c31b812d7b477e4c75ffc21b9b8b7fb91afb Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Fri, 24 Jan 2025 16:41:40 +0000 Subject: [PATCH 72/88] fix typo --- crush_example_freertos/sim/cpu_tb.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crush_example_freertos/sim/cpu_tb.v b/crush_example_freertos/sim/cpu_tb.v index b6e47bb..95cb0ba 100644 --- a/crush_example_freertos/sim/cpu_tb.v +++ b/crush_example_freertos/sim/cpu_tb.v @@ -30,7 +30,7 @@ wire rty_i = 0; wire timer_interrupt; -cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( +crush_cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), From efa9154d587ef79e498cac5b864002ddf0c53293 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 13:42:59 +0000 Subject: [PATCH 73/88] Increase test timeout --- .github/workflows/main.yml | 13 +++++++------ .github/workflows/simulate.yml | 6 +++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8dcc099..aa3b4f6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,15 +29,16 @@ jobs: project: crush_example target: ${{ matrix.target }} verilog-sim-crush-example-freertos: - strategy: - matrix: - target: - - sim_top - - sim_cpu uses: ./.github/workflows/simulate.yml with: project: crush_example_freertos - target: ${{ matrix.target }} + target: sim_cpu + verilog-sim-crush-example-freertos: + uses: ./.github/workflows/simulate.yml + with: + project: crush_example_freertos + target: sim_top + timeout-minutes: 10 verilog-lint: runs-on: ubuntu-22.04 container: diff --git a/.github/workflows/simulate.yml b/.github/workflows/simulate.yml index dc2f19f..52d6df5 100644 --- a/.github/workflows/simulate.yml +++ b/.github/workflows/simulate.yml @@ -9,6 +9,10 @@ on: target: required: true type: string + timeout-minutes: + default: 1 + required: false + type: number jobs: simulate: @@ -29,7 +33,7 @@ jobs: # also use the venv. echo PATH=$PATH >> $GITHUB_ENV - name: Run simulation - timeout-minutes: 1 + timeout-minutes: ${{ inputs.timeout-minutes }} run: | . script/init.sh fusesoc run --target ${{ inputs.target }} --resolve-env-vars-early ${{ inputs.project }} From b8406d6c152a532fea9def78b74f274117ed8d13 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 13:43:07 +0000 Subject: [PATCH 74/88] fix a lint --- crush/sim/inst_immediate_decode_tb.v | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crush/sim/inst_immediate_decode_tb.v b/crush/sim/inst_immediate_decode_tb.v index c17a25a..6ce45f3 100644 --- a/crush/sim/inst_immediate_decode_tb.v +++ b/crush/sim/inst_immediate_decode_tb.v @@ -10,6 +10,7 @@ wire[31:0] S_immediate; wire[31:0] B_immediate; wire[31:0] U_immediate; wire[31:0] J_immediate; +wire[31:0] CSR_immediate; inst_immediate_decode dut ( .inst(inst), @@ -17,7 +18,8 @@ inst_immediate_decode dut ( .S_immediate(S_immediate), .B_immediate(B_immediate), .U_immediate(U_immediate), - .J_immediate(J_immediate) + .J_immediate(J_immediate), + .CSR_immediate(CSR_immediate) ); initial begin From fec3358d70eb0f27ffd485aa63d00200ebfaa189 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 13:44:03 +0000 Subject: [PATCH 75/88] fix a lint --- crush/rtl/crush_cpu.v | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crush/rtl/crush_cpu.v b/crush/rtl/crush_cpu.v index ff7cd5b..49ccd0e 100644 --- a/crush/rtl/crush_cpu.v +++ b/crush/rtl/crush_cpu.v @@ -100,7 +100,9 @@ registers registers( assign r_address1 = instruction[19:15]; assign r_address2 = instruction[24:20]; assign w_address = instruction[11:7]; +`ifdef MACHINE_MODE wire [11:0] csr_address = instruction[31:20]; +`endif reg[31:0] alu_op_a; reg[31:0] alu_op_b; From 87185fa84b43d548164b61a6ac09ed33079fc969 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 13:49:25 +0000 Subject: [PATCH 76/88] fix lints --- crush/rtl/alu.v | 2 ++ crush/rtl/crush_cpu.v | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/crush/rtl/alu.v b/crush/rtl/alu.v index 1ed55f0..db354d4 100644 --- a/crush/rtl/alu.v +++ b/crush/rtl/alu.v @@ -21,7 +21,9 @@ module alu ( wire [31:0] B_immediate; wire [31:0] U_immediate; wire [31:0] J_immediate; + // verilator lint_off UNUSEDSIGNAL wire [31:0] CSR_immediate; + // verilator lint_on UNUSEDSIGNAL inst_immediate_decode immediate_decode ( .inst(instruction), diff --git a/crush/rtl/crush_cpu.v b/crush/rtl/crush_cpu.v index 49ccd0e..7996075 100644 --- a/crush/rtl/crush_cpu.v +++ b/crush/rtl/crush_cpu.v @@ -1,8 +1,11 @@ `default_nettype none module crush_cpu #( - parameter integer INITIAL_PC = 0, + parameter integer INITIAL_PC = 0 +`ifdef MACHINE_MODE + , parameter integer TRAP_PC = 0 +`endif ) ( input wire clk_i, input wire[31:0] dat_i, From b48f1ba20d702abd5ab10f9ce35c32c1785c376c Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 13:50:29 +0000 Subject: [PATCH 77/88] add comment --- crush/rtl/alu.v | 1 + 1 file changed, 1 insertion(+) diff --git a/crush/rtl/alu.v b/crush/rtl/alu.v index db354d4..105a237 100644 --- a/crush/rtl/alu.v +++ b/crush/rtl/alu.v @@ -21,6 +21,7 @@ module alu ( wire [31:0] B_immediate; wire [31:0] U_immediate; wire [31:0] J_immediate; + // False positive, because only used in machine mode // verilator lint_off UNUSEDSIGNAL wire [31:0] CSR_immediate; // verilator lint_on UNUSEDSIGNAL From 04f635fdbb716b2cf573b212a53b7da347062de9 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 14:30:37 +0000 Subject: [PATCH 78/88] Update waiver --- data/verilator_waiver.vlt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/verilator_waiver.vlt b/data/verilator_waiver.vlt index 32a5df7..aa6b488 100644 --- a/data/verilator_waiver.vlt +++ b/data/verilator_waiver.vlt @@ -30,5 +30,7 @@ lint_off -rule UNUSEDSIGNAL -file "*/sim/control.v" -match "Signal is not used: lint_off -rule UNUSEDSIGNAL -file "*/sim/control.v" -match "Signal is not used: 'we_i'" lint_off -file "*/yosys/ice40/cells_sim.v" +lint_off -file "*/simple_spi_top.v" lint_off -rule TIMESCALEMOD + From 50e6f407c968de2d4a39f56ac2649d959036315a Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 15:07:45 +0000 Subject: [PATCH 79/88] Update lint config --- crush_example_freertos/crush_example_freertos.core | 8 ++++++-- crush_example_freertos/rtl/spi.v | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 1627cea..2351ab4 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -76,7 +76,9 @@ targets: filesets: - verilator_waiver - rtl - - sim_top + # Can't lint because verilator fails on flash simulator: + # https://github.com/verilator/verilator/issues/5767 + # - sim_top - sim_cpu - sim_common tools: @@ -86,7 +88,9 @@ targets: - "-Wall -timing" # Disable default values in yosys's simulation modules. - "-DNO_ICE40_DEFAULT_ASSIGNMENTS" - toplevel: top_tb + toplevel: cpu_tb + parameters: + - MACHINE_MODE=true sim_cpu: <<: *default diff --git a/crush_example_freertos/rtl/spi.v b/crush_example_freertos/rtl/spi.v index b430413..5c58ef3 100644 --- a/crush_example_freertos/rtl/spi.v +++ b/crush_example_freertos/rtl/spi.v @@ -31,8 +31,6 @@ module spi #( wire addressed = (adr_i >= BASE_ADDRESS) & (adr_i < BASE_ADDRESS + 4 * 32'h10); wire[31:0] address = adr_i - BASE_ADDRESS; - // Interrupt output is ignored. The CPU is programmed to send commands slow - // enough that we will not overflow the FIFOs without using the interrupt. simple_spi spi ( // Wishbone .clk_i (clk_i), @@ -48,7 +46,12 @@ module spi #( .sck_o (flash_clk), .ss_o (flash_cs_n), .mosi_o (flash_mosi), - .miso_i (flash_miso) + .miso_i (flash_miso), + // Interrupt output is ignored. The CPU is programmed to send commands + // slow enough that we will not overflow the FIFOs. + // verilator lint_off PINCONNECTEMPTY + .inta_o () + // verilator lint_on PINCONNECTEMPTY ); assign err_o = 0; From 26e02eb74ef51bc6348be8b285badf5d791b3695 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 15:18:10 +0000 Subject: [PATCH 80/88] fix lints --- crush/rtl/alu.v | 1 + crush_example_freertos/sim/cpu_tb.v | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/crush/rtl/alu.v b/crush/rtl/alu.v index 105a237..943f98a 100644 --- a/crush/rtl/alu.v +++ b/crush/rtl/alu.v @@ -91,6 +91,7 @@ module alu ( FUNCT3_CSRRCI: out = op_a & ~CSR_immediate; FUNCT3_CSRRS: out = op_a | op_b; FUNCT3_CSRRSI: out = op_a | CSR_immediate; + default: ; endcase `endif default: ; diff --git a/crush_example_freertos/sim/cpu_tb.v b/crush_example_freertos/sim/cpu_tb.v index 95cb0ba..25cef2f 100644 --- a/crush_example_freertos/sim/cpu_tb.v +++ b/crush_example_freertos/sim/cpu_tb.v @@ -25,8 +25,8 @@ wire[31:0] dat_i; wire[31:0] dat_o; wire we_o; wire ack_i; -wire err_i = 0; -wire rty_i = 0; +wire err_i; +wire rty_i; wire timer_interrupt; @@ -48,6 +48,8 @@ crush_cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( ); wire ram_ack_o; +wire ram_err_o; +wire ram_rty_o; memory_infer #(.BASE_ADDRESS('h1000_0000), .SIZE('h1_0000)) ram ( .clk_i(clk), .rst_i(reset), @@ -59,8 +61,8 @@ memory_infer #(.BASE_ADDRESS('h1000_0000), .SIZE('h1_0000)) ram ( .dat_o(dat_i), .we_i(we_o), .ack_o(ram_ack_o), - .err_o(err_i), - .rty_o(rty_i) + .err_o(ram_err_o), + .rty_o(ram_rty_o) ); initial begin @@ -83,6 +85,8 @@ initial begin end wire mtimer_ack_o; +wire mtimer_err_o; +wire mtimer_rty_o; mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( .clk_i(clk), .rst_i(reset), @@ -94,8 +98,8 @@ mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( .dat_o(dat_i), .we_i(we_o), .ack_o(mtimer_ack_o), - .err_o(err_i), - .rty_o(rty_i), + .err_o(mtimer_err_o), + .rty_o(mtimer_rty_o), .interrupt(timer_interrupt) ); @@ -104,8 +108,11 @@ wire gpio_rty_o; wire gpio_err_o; wire [5:0] unused; reg btn = 0; +// verilator lint_off UNUSEDSIGNAL +// standin for GPIO going off the board reg led1; reg led2; +// verilator lint_on UNUSEDSIGNAL gpio #(.BASE_ADDRESS('h4000_0000)) gpio ( .clk_i(clk), .rst_i(reset), @@ -124,6 +131,8 @@ gpio #(.BASE_ADDRESS('h4000_0000)) gpio ( ); assign ack_i = ram_ack_o | mtimer_ack_o | gpio_ack_o; +assign rty_i = ram_rty_o | mtimer_rty_o | gpio_rty_o; +assign err_i = ram_err_o | mtimer_err_o | gpio_err_o; always begin #42 clk <= !clk; From feba36ebd37f1bcc3a56401866850bae6d50ea36 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 15:30:25 +0000 Subject: [PATCH 81/88] fix all lints --- crush/rtl/crush_cpu.v | 3 ++- crush/rtl/params.vh | 1 + crush/sim/csr_tb.v | 22 +++++++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/crush/rtl/crush_cpu.v b/crush/rtl/crush_cpu.v index 7996075..35d24cc 100644 --- a/crush/rtl/crush_cpu.v +++ b/crush/rtl/crush_cpu.v @@ -186,6 +186,7 @@ always @(posedge(clk_i)) begin CSR_MIE: csr_read_value <= mie; CSR_MEPC: csr_read_value <= mepc; CSR_MCAUSE: csr_read_value <= mcause; + CSR_MTVEC: csr_read_value <= mtvec; default: ; endcase end @@ -376,7 +377,7 @@ always @(*) begin we_o = 1'hx; trap_taken = 1; - pc_value = TRAP_PC; + pc_value = mtvec; pc_load = 1; if(instruction_is_ecall) begin diff --git a/crush/rtl/params.vh b/crush/rtl/params.vh index 103e926..47210c9 100644 --- a/crush/rtl/params.vh +++ b/crush/rtl/params.vh @@ -59,6 +59,7 @@ localparam FUNCT3_PRIV = 3'b000; localparam CSR_MSTATUS = 12'h300; localparam CSR_MIE = 12'h304; +localparam CSR_MTVEC = 12'h305; localparam CSR_MEPC = 12'h341; localparam CSR_MCAUSE = 12'h342; diff --git a/crush/sim/csr_tb.v b/crush/sim/csr_tb.v index ca99458..92be8f9 100644 --- a/crush/sim/csr_tb.v +++ b/crush/sim/csr_tb.v @@ -1,4 +1,15 @@ /* Test bench for CSR instructions CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI */ + test_case("CSRRCI"); + + cpu.mepc = 32'h0000_0014; + + CSRRCI(1, CSR_MEPC, 5'h18); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0014); + `fatal_assert (cpu.mepc == 32'h0000_0004); + #1; /* Most of the implemented CSRs are not arbitrary read/write registers. Instead * they are WARL etc. @@ -34,7 +45,7 @@ string test_case_name = ""; reg flash_ack_o = 0; reg[31:0] flash_dat_o = 32'hzzzz_zzzz; -crush_cpu #(.INITIAL_PC('h1000_0000)) cpu ( +crush_cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1234_5678) cpu ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), @@ -252,6 +263,15 @@ initial begin `fatal_assert (cpu.mepc == 32'h0000_0004); #1; + test_case("read MTVEC"); + + CSRRW(1, CSR_MTVEC, 5'h0); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == (32'h1234_5678)); + #1; + $stop; end From ebe59575149f2e5c508e469e587e2ce9ddabee52 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 15:33:27 +0000 Subject: [PATCH 82/88] fix ci --- .github/workflows/main.yml | 4 ++-- crush_example_freertos/crush_example_freertos.core | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aa3b4f6..0abacc2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,12 +28,12 @@ jobs: with: project: crush_example target: ${{ matrix.target }} - verilog-sim-crush-example-freertos: + verilog-sim-crush-example-freertos-cpu: uses: ./.github/workflows/simulate.yml with: project: crush_example_freertos target: sim_cpu - verilog-sim-crush-example-freertos: + verilog-sim-crush-example-freertos-top: uses: ./.github/workflows/simulate.yml with: project: crush_example_freertos diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index 2351ab4..b321304 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -117,3 +117,7 @@ scripts: cmd: - echo - "Run 'iceprog ...' in the build folder to program the board" + iceprog_app_hint: + cmd: + - echo + - "Run 'iceprog -o 0x20000 freertos/app/build/crush_freertos.bin' to load firmware to flash." From 988d03e78adb2acb2cf02551ed7651bece730469 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 15:39:16 +0000 Subject: [PATCH 83/88] fix misplaced code --- crush/sim/csr_tb.v | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/crush/sim/csr_tb.v b/crush/sim/csr_tb.v index 92be8f9..7a29251 100644 --- a/crush/sim/csr_tb.v +++ b/crush/sim/csr_tb.v @@ -1,15 +1,4 @@ /* Test bench for CSR instructions CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI */ - test_case("CSRRCI"); - - cpu.mepc = 32'h0000_0014; - - CSRRCI(1, CSR_MEPC, 5'h18); - - #1; - @(cpu.state == cpu.STATE_FETCH); - `fatal_assert (cpu.registers.x1 == 32'h0000_0014); - `fatal_assert (cpu.mepc == 32'h0000_0004); - #1; /* Most of the implemented CSRs are not arbitrary read/write registers. Instead * they are WARL etc. @@ -45,7 +34,7 @@ string test_case_name = ""; reg flash_ack_o = 0; reg[31:0] flash_dat_o = 32'hzzzz_zzzz; -crush_cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1234_5678) cpu ( +crush_cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1234_5678)) cpu ( .clk_i(clk), .dat_i(dat_i), .dat_o(dat_o), From c46f32a60efaf2fe52accdff57fb35a5ede6b341 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 15:48:12 +0000 Subject: [PATCH 84/88] update CI --- .github/workflows/main.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0abacc2..4aa4063 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -112,6 +112,12 @@ jobs: fusesoc --verbose run ${{ matrix.project }} firmware: runs-on: ubuntu-22.04 + strategy: + matrix: + path: + - crush_example/fw + - crush_example_freertos/fw/spi_bootloader + - crush_example_freertos/fw/app container: image: barabas5532/crush-ci:4 defaults: @@ -123,10 +129,3 @@ jobs: run: cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=TC-crush.cmake - name: Build run: cmake --build build - - uses: actions/upload-artifact@v4 - with: - name: firmware-elf - path: | - fw/build/crush-blinky - fw/build/crush-blinky.bin - fw/build/crush-blinky.data From d97e0b56b30104c9ca5e1144b2fe6e3acacefea9 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 15:49:19 +0000 Subject: [PATCH 85/88] Fix CI --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4aa4063..8ecb9cd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -122,7 +122,7 @@ jobs: image: barabas5532/crush-ci:4 defaults: run: - working-directory: crush_example/fw + working-directory: ${{ matrix.path }} steps: - uses: actions/checkout@v4 - name: Configure From 57c051d2e46c4723bab5fe3b1b4e685be82b30cd Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 16:31:41 +0000 Subject: [PATCH 86/88] Update docs --- crush_example/crush_example.core | 2 +- crush_example_freertos/crush_example_freertos.core | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/crush_example/crush_example.core b/crush_example/crush_example.core index 36ec04a..2bcd49d 100644 --- a/crush_example/crush_example.core +++ b/crush_example/crush_example.core @@ -87,4 +87,4 @@ scripts: iceprog_hint: cmd: - echo - - "Run 'iceprog ...' in the build folder to program the board" + - "Run 'iceprog build/crush_example_0.0.1/default-icestorm/crush_example_0.0.1.bin' to program the board." diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core index b321304..6f4a911 100644 --- a/crush_example_freertos/crush_example_freertos.core +++ b/crush_example_freertos/crush_example_freertos.core @@ -59,6 +59,8 @@ targets: tools: icestorm: nextpnr_options : [ "--up5k", "--package", "sg48" ] + # disable final deep-sleep SPI flash command after bitstream is loaded + icepack_options : [ "-s" ] yosys_synth_options: - "-dsp" icarus: @@ -67,7 +69,9 @@ targets: - "-g2012" - "-gassertions" hooks: - post_run: [iceprog_hint] + post_run: + - iceprog_hint + - iceprog_app_hint parameters: - MACHINE_MODE=true @@ -116,8 +120,8 @@ scripts: iceprog_hint: cmd: - echo - - "Run 'iceprog ...' in the build folder to program the board" + - "Run 'iceprog build/crush_example_freertos_0.0.1/default-icestorm/crush_example_freertos_0.0.1.bin' to program the board." iceprog_app_hint: cmd: - echo - - "Run 'iceprog -o 0x20000 freertos/app/build/crush_freertos.bin' to load firmware to flash." + - "Run 'iceprog -o 0x20000 crush_example_freertos/fw/app/binary/crush_freertos.bin' to load firmware to flash." From 69e8f138c7a8edd3571cb4cc471c19eff305bfbf Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 6 Feb 2025 16:56:48 +0000 Subject: [PATCH 87/88] try fix for freertos linking --- crush_example_freertos/fw/app/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/crush_example_freertos/fw/app/CMakeLists.txt b/crush_example_freertos/fw/app/CMakeLists.txt index 690a119..e23dcdd 100644 --- a/crush_example_freertos/fw/app/CMakeLists.txt +++ b/crush_example_freertos/fw/app/CMakeLists.txt @@ -45,6 +45,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE freertos_kernel) # Since we use -nostdlib, we must link to libgcc manually target_link_libraries(${PROJECT_NAME} PRIVATE gcc) +target_link_libraries(freertos_kernel PRIVATE gcc) string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) find_program(objcopy_program ${objcopy_name} REQUIRED) From 0d4683f1d8175151005b223a80a10518455db0f7 Mon Sep 17 00:00:00 2001 From: Barabas Raffai Date: Thu, 13 Feb 2025 14:37:21 +0000 Subject: [PATCH 88/88] Revert "try fix for freertos linking" This reverts commit 69e8f138c7a8edd3571cb4cc471c19eff305bfbf. --- crush_example_freertos/fw/app/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/crush_example_freertos/fw/app/CMakeLists.txt b/crush_example_freertos/fw/app/CMakeLists.txt index e23dcdd..690a119 100644 --- a/crush_example_freertos/fw/app/CMakeLists.txt +++ b/crush_example_freertos/fw/app/CMakeLists.txt @@ -45,7 +45,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE freertos_kernel) # Since we use -nostdlib, we must link to libgcc manually target_link_libraries(${PROJECT_NAME} PRIVATE gcc) -target_link_libraries(freertos_kernel PRIVATE gcc) string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) find_program(objcopy_program ${objcopy_name} REQUIRED)