📄 memory_sizer_dual_path.v
字号:
//----------------------------------------------------------------------------// Wishbone memory_sizer_dual_path core//// This file is part of the "memory_sizer" project.// http://www.opencores.org/cores/memory_sizer// //// Description: See description below (which suffices for IP core// specification document.)//// Copyright (C) 2001 John Clayton and OPENCORES.ORG//// This source file may be used and distributed without restriction provided// that this copyright statement is not removed from the file and that any// derivative work contains the original copyright notice and the associated// disclaimer.//// This source file is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published// by the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// This source is distributed in the hope that it will be useful, but WITHOUT// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public// License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with this source.// If not, download it from http://www.opencores.org/lgpl.shtml////----------------------------------------------------------------------------//// Author: John Clayton// Date : November 5, 2001// Update: 11/05/01 copied this file from rs232_syscon.v (pared down).// Update: 11/16/01 Continued coding efforts. Redesigned logic with scalable// "byte sized barrel shifter" and byte reversal blocks (byte// reversal is implemented as a function "byte_reversal").// Changed encoding of memory_width_i and access_width_i.// Implemented new counting and byte enable logic.// Update: 12/04/01 Realized there was a mistake in the byte enable logic.// Fixed it by using dat_shift to shift the byte enables.// Made "byte_enable_source" twice as wide.// Update: 12/05/01 Eliminated the "count" in favor of using "dat_shift" along// with new terminal_count logic, in order to fix flaws found// in the terminal_count signal. Fixed byte steering for// stores. Tested using N_PP = 4, and LOG2_N_PP = 2 and saw// correct operation for all sizes of store operations.// Update: 12/13/01 Began testing with read logic. Found byte enable problem// during writes. Removed "byte_dirty" bits.// Update: 12/14/01 Added "latch_be_source" to create byte enables for reading// which are based on the size of the memory (which fixed a// bug in reading.) The module appears to be fully working,// except for "big_endian" reads.// Update: 12/17/01 Introduced the "middle_bus" in order to decouple the// byte reverser from the byte steering logic, so that for// writes byte reversing is done first, but for reads then// byte reversing is done last. Introduced "latch_be_adjust"// to cover big endian reads -- all is now working.// Update: 12/17/01 Removed "middle_bus" (the two units are still decoupled!)// because it seemed unnecessary. This freed up Tbuffs, but// had no effect on resource utilization (slices). Also, the// maximum reported clock speed increased. Removed debug// port.// Update: 12/18/01 Copied this from "memory_sizer_tristate_switching.v"// This file will now have duplicate byte steering and byte// swapping logic. Changed module name to // "memory_sizer_dual_path"//// Description//-------------------------------------------------------------------------------------//// This module is just like "memory_sizer" except that it provides separate// paths for the writing and the reading of memory. By avoiding the tri-state// bus switching, it uses less tri-state buffers, and should operate faster// than the original "memory_sizer"//// ORIGINAL DESCRIPTION:// This logic module takes care of sizing bus transfers between a small// microprocessor and its memory. It enables the microprocessor to// generate access requests for different widths (read/write BYTE, WORD and// DWORD, etc.) using memory which is sized independently of the accesses.//// Thus, a 32-bit microprocessor using 32-bit wide accesses can use this block// in order to boot from an 8-bit wide flash device. This block takes care of // generating the four 8-bit memory cycles that are required in order to read// each DWORD for alimentation of the microprocessor.//// Also, if the memory supports byte enables during a write cycle, then this// block "steers" a smaller data word to the appropriate location within a// larger memory word, and activates the appropriate byte enables so that only// the BYTEs which are affected by the write cycle are actually overwritten.//// Moreover, the memory_sizer block takes care of translating little-endian// formats into big-endian formats and vice-versa. This is accomplished by the// use of a single input bit "endianness_i"//// The memory_sizer block does not latch or store the parameters which it uses// for operation. The input signals determine its operation on an ongoing// basis. In fact, the only data storage present in this block is the latching// provided for data which must be held during multiple cycle read operations.// (There are also some counters, which don't count as data storage...)//// Encoding for access_width_i and memory_width_i is as follows://// Bits Significance// ------ ------------// 0001 8-bits wide (1 byte)// 0010 16-bits wide (2 bytes)// 0100 32-bits wide (4 bytes)// 1000 64-bits wide (8 bytes)//// (The access_width_i and memory_width_i inputs are sized according to the// parameter LOG2_N_PP, but the significance is the same, using whatever// lsbs are present.)//// It is envisioned that a designer may include this block for flexibility.// If all of the memory accesses are of a single width, and the memory matches// that width, and there is no need for endianness translation, then the user// could hard-code the "memory_width_i" and "access_width_i" to correspond// to the same width, hard-code the "endianness_i" input to the desired value// and then the memory_sizer block would effectively do nothing, or very little.// Most of its size and resources would be optimized out of the design at// compile time. The dat_shift counter and read-storage latches would not be// used, and so they would not even be synthesized.//// On the other hand, if the memory in the SOC (system on a chip) comprises// various width devices, then the decode logic which selects the blocks of// memory is ORed (for each like-sized block) and then concatenated in the// proper order to generate a dynamic "mem_width_i" signal to the// memory_sizer, so that the different size accesses are accomodated. The// processor side, meanwhile (being "access_width_i"), could still be// hard-wired to a given width, or be connected so that different width loads// and stores are generated as needed.//// This block may generate exceptions to the processor, in the case of a write// request, for example, to store a BYTE into a DWORD wide memory which doesn't// support the use of byte enables. Although this could be done by reading the// wider memory and masking in the correct BYTE, followed by storing the// results back into the memory, this was deemed too complex a task for this// block. Responsibility for such operations, if desired, would devolve upon// the microprocessor itself. Support of byte enables is indicated by a "1" on// the "memory_has_be_i" line.//// The clock used by memory_sizer is not limited to the speed of the clock used// by the microprocessor. Since the memory_sizer contains only combinational// logic, simple counters and some possible latches, it might run much faster// than the microprocessor. In that case, generate two clocks which are// synchronous: one for the processor, and another for memory_sizer.// The memory_sizer clock could be 2x, 4x or even 8x that of the processor.// In this way, the memory_sizer block can complete multiple memory read cycles// in the same time as a single processor cycle -- assuming the memory is fast// enough to support it -- and thereby the memory latency can be reduced.//// The memory_sizer block is not responsible for implementing wait states for// the memory, especially since the number of wait states required can vary// for each type and width of memory used. Instead, there is an "access_ack_o"// signal to indicate completion of the entire requested memory access to the// processor. On the memory side, there is "memory_ack_i" used to indicate to// the memory_sizer block that the memory has completed the current cycle in// progress. Therefore, in order to implement wait states, the memory sytem// address decoder logic should generate the "memory_ack_i" signal based on the// different types of memory present within the system, which can also be// programmable. A parameterized watchdog timer inside of the memory sizer block// indicates when "memory_ack_i" has not been asserted in a reasonable number// of clock cycles. When this occurs, an exception is raised. The timer// is started when "sel_i" is active (high). sel_i must remain active// until the access is completed, otherwise the timer will reset and the// access is aborted. If you don't want to use the watchdog portion of this// block then simply don't connect the exception_watchdog_o line, and the watchdog// timer will be optimized out of the logic.//// If desired, registers can be placed on the memory side of the block. They// are treated just like memory of a given width, although access requests for// misaligned writes, or writes which are smaller than the size of the registers,// should generate exceptions, unless the registers support byte enables.//// Addresses are always assumed to be byte addresses in this unit, since the// smallest granularity of data used in it is the BYTE. Also, the data bus// size used must be a multiple of 8 bits, for the same reason.////-------------------------------------------------------------------------------------`define BYTE_SIZE 8 // Number of bits in one bytemodule memory_sizer_dual_path ( clk_i, reset_i, sel_i, memory_ack_i, memory_has_be_i, memory_width_i, access_width_i, access_big_endian_i, adr_i, we_i, dat_io, memory_dat_io, memory_adr_o, // Same width as adr_i (only lsbs are modified) memory_we_o, memory_be_o, access_ack_o, exception_be_o, exception_watchdog_o );// Parameters// The timer value can be from [0 to (2^WATCHDOG_TIMER_BITS_PP)-1] inclusive.parameter N_PP = 4; // number of bytes in data busparameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes)parameter ADR_BITS_PP = 32; // # of bits in adr busesparameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expectedparameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer// I/O declarationsinput clk_i; // Memory sub-system clock inputinput reset_i; // Reset signal for this moduleinput sel_i; // Enables watchdog timer, activates memory_sizerinput memory_ack_i; // Ack from memory (delay for wait states)input memory_has_be_i; // Indicates memory at current address has byte enablesinput [LOG2_N_PP:0] memory_width_i; // Width code of memoryinput [LOG2_N_PP:0] access_width_i; // Width code of access requestinput access_big_endian_i; // 0=little endian, 1=big endianinput [ADR_BITS_PP-1:0] adr_i; // Address bus inputinput we_i; // type of accessinout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data businout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memoryoutput [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memoryoutput memory_we_o; // we to memoryoutput [N_PP-1:0] memory_be_o; // byte enables to memoryoutput access_ack_o; // shows that access is completedoutput exception_be_o; // exception for write to non-byte-enabled memoryoutput exception_watchdog_o; // exception for memory_ack_i watch dog timeout
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -