OpenCores
URL https://opencores.org/ocsvn/memory_sizer/memory_sizer/trunk

Subversion Repositories memory_sizer

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/tags/V001/b10_safe_12_18_01_single_path.zip Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
tags/V001/b10_safe_12_18_01_single_path.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: tags/V001/memory_sizer_dual_path.v =================================================================== --- tags/V001/memory_sizer_dual_path.v (revision 3) +++ tags/V001/memory_sizer_dual_path.v (nonexistent) @@ -1,477 +0,0 @@ -//---------------------------------------------------------------------------- -// 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 byte - - -module 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 bus -parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes) -parameter ADR_BITS_PP = 32; // # of bits in adr buses -parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected -parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer - - -// I/O declarations -input clk_i; // Memory sub-system clock input -input reset_i; // Reset signal for this module -input sel_i; // Enables watchdog timer, activates memory_sizer -input memory_ack_i; // Ack from memory (delay for wait states) -input memory_has_be_i; // Indicates memory at current address has byte enables -input [LOG2_N_PP:0] memory_width_i; // Width code of memory -input [LOG2_N_PP:0] access_width_i; // Width code of access request -input access_big_endian_i; // 0=little endian, 1=big endian -input [ADR_BITS_PP-1:0] adr_i; // Address bus input -input we_i; // type of access -inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus -inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory -output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory -output memory_we_o; // we to memory -output [N_PP-1:0] memory_be_o; // byte enables to memory -output access_ack_o; // shows that access is completed -output exception_be_o; // exception for write to non-byte-enabled memory -output exception_watchdog_o; // exception for memory_ack_i watch dog timeout - -// Internal signal declarations -wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing -wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading -wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" -wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads. -wire [N_PP-1:0] latch_be_big_endian; -wire [LOG2_N_PP-1:0] latch_be_adjust; -wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit - // is for terminal count compare.) -wire [LOG2_N_PP-1:0] alignment; // shows aligment of access -wire terminal_count; // signifies last store cycle - -reg [LOG2_N_PP-1:0] rd_byte_mux_select; // selects which bytes to transfer -reg [LOG2_N_PP-1:0] wr_byte_mux_select; // selects which bytes to transfer -reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables -reg [`BYTE_SIZE*N_PP-1:0] wr_steer_dat_o; // data from byte steering logic -reg [`BYTE_SIZE*N_PP-1:0] wr_revrs_dat_o; // data from byte reversing logic -reg [`BYTE_SIZE*N_PP-1:0] rd_revrs_dat_o; // data from byte reversing logic -reg [`BYTE_SIZE*N_PP-1:0] rd_steer_dat_o; // data from byte steering logic -reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing) -reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass - - -reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count; - -//-------------------------------------------------------------------------- -// Instantiations -//-------------------------------------------------------------------------- - - -//-------------------------------------------------------------------------- -// Functions & Tasks -//-------------------------------------------------------------------------- - -function [`BYTE_SIZE*N_PP-1:0] byte_reversal; - input [`BYTE_SIZE*N_PP-1:0] din; - integer k; - begin - for (k=0; k> dat_shift) - :{N_PP{1'b1}}; - // (memory byte enables are all high for reads!) - -// For big_endian reads, the latch byte enables (and indeed the data also) -// are shifted using a special mapping, which causes the data to appear at -// the opposite end of the "read_data" bus. -assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment); -assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1); -assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust; -assign latch_be = (access_big_endian_i)?latch_be_big_endian - :latch_be_lil_endian; - -// Exceptions -assign exception_be_o = (alignment != 0) && ~memory_has_be_i; -assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP); - -// Pass signals to memory -assign memory_we_o = we_i; - - -// Enable the data bus outputs in each direction -assign dat_io = (sel_i && ~we_i)?rd_revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; -assign memory_dat_io = (sel_i && we_i)?wr_steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; - - - -// THIS LOGIC IS FOR THE WRITING PATH -//------------------------------------- -// Byte reversal logic -always @( - dat_io or - access_big_endian_i - ) -begin - // Reverse the bytes of the data bus, if needed - if (access_big_endian_i) wr_revrs_dat_o <= byte_reversal(dat_io); - else wr_revrs_dat_o <= dat_io; -end - - -// Steering logic -always @( - wr_revrs_dat_o or - dat_shift or - alignment or - we_i or - access_width_i or - access_big_endian_i - ) -begin - // If bytes are reversed, an extra "bit inversion mask" is applied - // to reflect a new mapping which is correct for reversed bytes. - if (access_big_endian_i) - wr_byte_mux_select <= (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)) - - alignment; - else wr_byte_mux_select <= dat_shift - alignment; - - // Rotate the data bus (byte-sized barrel shifter!) - wr_steer_dat_o <= ( - (wr_revrs_dat_o >> `BYTE_SIZE*wr_byte_mux_select) - |(wr_revrs_dat_o << `BYTE_SIZE*(N_PP-wr_byte_mux_select)) - ); -end - - -// THIS LOGIC IS FOR THE READING PATH -//------------------------------------- - -// Steering logic -always @( - memory_dat_io or - dat_shift or - alignment or - we_i or - access_width_i or - access_big_endian_i - ) -begin - // For reads, negate the shift amount - if (access_big_endian_i) - rd_byte_mux_select <= alignment - - (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)); - else rd_byte_mux_select <= alignment - dat_shift; - - // Rotate the data bus (byte-sized barrel shifter!) - rd_steer_dat_o <= ( - (memory_dat_io >> `BYTE_SIZE*rd_byte_mux_select) - |(memory_dat_io << `BYTE_SIZE*(N_PP-rd_byte_mux_select)) - ); -end - - -// This logic latches the data bytes which are read during the first cycles -// of an access. During the final cycle of the access, then "terminal_count" -// is asserted by the counting logic, which causes the latches which are -// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes. -// This means that for single cycle accesses, the data will flow directly -// around the latches and an extra clock cycle will not be needed in order -// to latch the data... -always @(posedge clk_i) -begin: BYTE_LATCHES - integer i; - - if (reset_i || terminal_count || ~sel_i) - begin - latched_read_dat <= 0; - end - else if (sel_i && ~we_i && memory_ack_i) - begin - for (i=0;i= (access_width_i + alignment)); -assign memory_adr_o = adr_i + dat_shift; -assign access_ack_o = terminal_count && sel_i; - -// This is the watchdog timer -// It runs whenever the memory_sizer is selected for an access, and the -// memory has not yet responded with an ack signal. -always @(posedge clk_i) -begin - if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; - else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1; -end - - -endmodule - - Index: tags/V001/b10_safe_12_18_01_dual_path.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: tags/V001/b10_safe_12_18_01_dual_path.zip =================================================================== --- tags/V001/b10_safe_12_18_01_dual_path.zip (revision 3) +++ tags/V001/b10_safe_12_18_01_dual_path.zip (nonexistent)
tags/V001/b10_safe_12_18_01_dual_path.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: trunk/b10_safe_12_18_01_dual_path.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: trunk/b10_safe_12_18_01_dual_path.zip =================================================================== --- trunk/b10_safe_12_18_01_dual_path.zip (revision 3) +++ trunk/b10_safe_12_18_01_dual_path.zip (nonexistent)
trunk/b10_safe_12_18_01_dual_path.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: trunk/memory_sizer.v =================================================================== --- trunk/memory_sizer.v (revision 3) +++ trunk/memory_sizer.v (nonexistent) @@ -1,444 +0,0 @@ -//---------------------------------------------------------------------------- -// Wishbone memory_sizer 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 to include scalable -// "byte sized barrel shifter" and byte reversal blocks (the 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 Added file header according to opencores recommendations. -// -// 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 byte - - -module memory_sizer ( - 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 bus -parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes) -parameter ADR_BITS_PP = 32; // # of bits in adr buses -parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected -parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer - - -// I/O declarations -input clk_i; // Memory sub-system clock input -input reset_i; // Reset signal for this module -input sel_i; // Enables watchdog timer, activates memory_sizer -input memory_ack_i; // Ack from memory (delay for wait states) -input memory_has_be_i; // Indicates memory at current address has byte enables -input [LOG2_N_PP:0] memory_width_i; // Width code of memory -input [LOG2_N_PP:0] access_width_i; // Width code of access request -input access_big_endian_i; // 0=little endian, 1=big endian -input [ADR_BITS_PP-1:0] adr_i; // Address bus input -input we_i; // type of access -inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus -inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory -output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory -output memory_we_o; // we to memory -output [N_PP-1:0] memory_be_o; // byte enables to memory -output access_ack_o; // shows that access is completed -output exception_be_o; // exception for write to non-byte-enabled memory -output exception_watchdog_o; // exception for memory_ack_i watch dog timeout - -// Internal signal declarations -wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing -wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading -wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" -wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads. -wire [N_PP-1:0] latch_be_big_endian; -wire [LOG2_N_PP-1:0] latch_be_adjust; -wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit - // is for terminal count compare.) -wire [LOG2_N_PP-1:0] alignment; // shows aligment of access -wire terminal_count; // signifies last store cycle -wire [`BYTE_SIZE*N_PP-1:0] steer_dat_i; // data input to byte steering logic -wire [`BYTE_SIZE*N_PP-1:0] revrs_dat_i; // data input to byte reversing logic - -reg [LOG2_N_PP-1:0] byte_mux_select; // selects which bytes to transfer -reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables -reg [`BYTE_SIZE*N_PP-1:0] revrs_dat_o; // data out from byte reversing logic -reg [`BYTE_SIZE*N_PP-1:0] steer_dat_o; // data out from byte steering logic -reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing) -reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass - - -reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count; - -//-------------------------------------------------------------------------- -// Instantiations -//-------------------------------------------------------------------------- - - -//-------------------------------------------------------------------------- -// Functions & Tasks -//-------------------------------------------------------------------------- - -function [`BYTE_SIZE*N_PP-1:0] byte_reversal; - input [`BYTE_SIZE*N_PP-1:0] din; - integer k; - begin - for (k=0; k> dat_shift) - :{N_PP{1'b1}}; - // (memory byte enables are all high for reads!) - -// For big_endian reads, the latch byte enables (and indeed the data also) -// are shifted using a special mapping, which causes the data to appear at -// the opposite end of the "read_data" bus. -assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment); -assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1); -assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust; -assign latch_be = (access_big_endian_i)?latch_be_big_endian - :latch_be_lil_endian; - -// Exceptions -assign exception_be_o = (alignment != 0) && ~memory_has_be_i; -assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP); - -// Pass signals to memory -assign memory_we_o = we_i; - - -// Enable the data bus outputs in each direction -assign dat_io = (sel_i && ~we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; -assign memory_dat_io = (sel_i && we_i)?steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; - -// Decide which bus supplies the byte reversing logic -// (One could just use a single mux here instead of the tri-state buffers. -// in fact, the synthesis tool might decide to change the tri-state buffers -// into simple 2:1 muxes...) -assign revrs_dat_i = (~we_i)?read_dat:{`BYTE_SIZE*N_PP{1'bZ}}; -assign revrs_dat_i = (we_i)?dat_io:{`BYTE_SIZE*N_PP{1'bZ}}; - - -// Decide which bus supplies the byte steering logic -// (One could just use a single mux here instead of the tri-state buffers. -// in fact, the synthesis tool might decide to change the tri-state buffers -// into simple 2:1 muxes...) -assign steer_dat_i = (~we_i)?memory_dat_io:{`BYTE_SIZE*N_PP{1'bZ}}; -assign steer_dat_i = (we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; - - -// This logic latches the data bytes which are read during the first cycles -// of an access. During the final cycle of the access, then "terminal_count" -// is asserted by the counting logic, which causes the latches which are -// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes. -// This means that for single cycle accesses, the data will flow directly -// around the latches and an extra clock cycle will not be needed in order -// to latch the data... -always @(posedge clk_i) -begin: BYTE_LATCHES - integer i; - - if (reset_i || terminal_count || ~sel_i) - begin - latched_read_dat <= 0; - end - else if (sel_i && ~we_i && memory_ack_i) - begin - for (i=0;i> `BYTE_SIZE*byte_mux_select) - |(steer_dat_i << `BYTE_SIZE*(N_PP-byte_mux_select)) - ); -end - - -// This is the counting logic. -// It is implemented using "count_next" in order to detect when -// the last cycle is being performed, which is when the "next" count -// equals or exceeds the total size of the access requested in bytes. -// (Using the "next" approach avoids issues relating to different -// memory sizes!) -always @(posedge clk_i) -begin - if (reset_i || terminal_count || ~sel_i) dat_shift <= 0; - else if (memory_ack_i) dat_shift <= dat_shift_next; -end - -assign dat_shift_next = dat_shift + memory_width_i; -assign terminal_count = (dat_shift_next >= (access_width_i + alignment)); -assign memory_adr_o = adr_i + dat_shift; -assign access_ack_o = terminal_count && sel_i; - -// This is the watchdog timer -// It runs whenever the memory_sizer is selected for an access, and the -// memory has not yet responded with an ack signal. -always @(posedge clk_i) -begin - if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; - else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1; -end - - -endmodule - - Index: trunk/b10_safe_12_18_01_single_path.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: trunk/b10_safe_12_18_01_single_path.zip =================================================================== --- trunk/b10_safe_12_18_01_single_path.zip (revision 3) +++ trunk/b10_safe_12_18_01_single_path.zip (nonexistent)
trunk/b10_safe_12_18_01_single_path.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: trunk/memory_sizer_dual_path.v =================================================================== --- trunk/memory_sizer_dual_path.v (revision 3) +++ trunk/memory_sizer_dual_path.v (nonexistent) @@ -1,477 +0,0 @@ -//---------------------------------------------------------------------------- -// 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 byte - - -module 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 bus -parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes) -parameter ADR_BITS_PP = 32; // # of bits in adr buses -parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected -parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer - - -// I/O declarations -input clk_i; // Memory sub-system clock input -input reset_i; // Reset signal for this module -input sel_i; // Enables watchdog timer, activates memory_sizer -input memory_ack_i; // Ack from memory (delay for wait states) -input memory_has_be_i; // Indicates memory at current address has byte enables -input [LOG2_N_PP:0] memory_width_i; // Width code of memory -input [LOG2_N_PP:0] access_width_i; // Width code of access request -input access_big_endian_i; // 0=little endian, 1=big endian -input [ADR_BITS_PP-1:0] adr_i; // Address bus input -input we_i; // type of access -inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus -inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory -output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory -output memory_we_o; // we to memory -output [N_PP-1:0] memory_be_o; // byte enables to memory -output access_ack_o; // shows that access is completed -output exception_be_o; // exception for write to non-byte-enabled memory -output exception_watchdog_o; // exception for memory_ack_i watch dog timeout - -// Internal signal declarations -wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing -wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading -wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" -wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads. -wire [N_PP-1:0] latch_be_big_endian; -wire [LOG2_N_PP-1:0] latch_be_adjust; -wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit - // is for terminal count compare.) -wire [LOG2_N_PP-1:0] alignment; // shows aligment of access -wire terminal_count; // signifies last store cycle - -reg [LOG2_N_PP-1:0] rd_byte_mux_select; // selects which bytes to transfer -reg [LOG2_N_PP-1:0] wr_byte_mux_select; // selects which bytes to transfer -reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables -reg [`BYTE_SIZE*N_PP-1:0] wr_steer_dat_o; // data from byte steering logic -reg [`BYTE_SIZE*N_PP-1:0] wr_revrs_dat_o; // data from byte reversing logic -reg [`BYTE_SIZE*N_PP-1:0] rd_revrs_dat_o; // data from byte reversing logic -reg [`BYTE_SIZE*N_PP-1:0] rd_steer_dat_o; // data from byte steering logic -reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing) -reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass - - -reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count; - -//-------------------------------------------------------------------------- -// Instantiations -//-------------------------------------------------------------------------- - - -//-------------------------------------------------------------------------- -// Functions & Tasks -//-------------------------------------------------------------------------- - -function [`BYTE_SIZE*N_PP-1:0] byte_reversal; - input [`BYTE_SIZE*N_PP-1:0] din; - integer k; - begin - for (k=0; k> dat_shift) - :{N_PP{1'b1}}; - // (memory byte enables are all high for reads!) - -// For big_endian reads, the latch byte enables (and indeed the data also) -// are shifted using a special mapping, which causes the data to appear at -// the opposite end of the "read_data" bus. -assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment); -assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1); -assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust; -assign latch_be = (access_big_endian_i)?latch_be_big_endian - :latch_be_lil_endian; - -// Exceptions -assign exception_be_o = (alignment != 0) && ~memory_has_be_i; -assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP); - -// Pass signals to memory -assign memory_we_o = we_i; - - -// Enable the data bus outputs in each direction -assign dat_io = (sel_i && ~we_i)?rd_revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; -assign memory_dat_io = (sel_i && we_i)?wr_steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; - - - -// THIS LOGIC IS FOR THE WRITING PATH -//------------------------------------- -// Byte reversal logic -always @( - dat_io or - access_big_endian_i - ) -begin - // Reverse the bytes of the data bus, if needed - if (access_big_endian_i) wr_revrs_dat_o <= byte_reversal(dat_io); - else wr_revrs_dat_o <= dat_io; -end - - -// Steering logic -always @( - wr_revrs_dat_o or - dat_shift or - alignment or - we_i or - access_width_i or - access_big_endian_i - ) -begin - // If bytes are reversed, an extra "bit inversion mask" is applied - // to reflect a new mapping which is correct for reversed bytes. - if (access_big_endian_i) - wr_byte_mux_select <= (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)) - - alignment; - else wr_byte_mux_select <= dat_shift - alignment; - - // Rotate the data bus (byte-sized barrel shifter!) - wr_steer_dat_o <= ( - (wr_revrs_dat_o >> `BYTE_SIZE*wr_byte_mux_select) - |(wr_revrs_dat_o << `BYTE_SIZE*(N_PP-wr_byte_mux_select)) - ); -end - - -// THIS LOGIC IS FOR THE READING PATH -//------------------------------------- - -// Steering logic -always @( - memory_dat_io or - dat_shift or - alignment or - we_i or - access_width_i or - access_big_endian_i - ) -begin - // For reads, negate the shift amount - if (access_big_endian_i) - rd_byte_mux_select <= alignment - - (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)); - else rd_byte_mux_select <= alignment - dat_shift; - - // Rotate the data bus (byte-sized barrel shifter!) - rd_steer_dat_o <= ( - (memory_dat_io >> `BYTE_SIZE*rd_byte_mux_select) - |(memory_dat_io << `BYTE_SIZE*(N_PP-rd_byte_mux_select)) - ); -end - - -// This logic latches the data bytes which are read during the first cycles -// of an access. During the final cycle of the access, then "terminal_count" -// is asserted by the counting logic, which causes the latches which are -// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes. -// This means that for single cycle accesses, the data will flow directly -// around the latches and an extra clock cycle will not be needed in order -// to latch the data... -always @(posedge clk_i) -begin: BYTE_LATCHES - integer i; - - if (reset_i || terminal_count || ~sel_i) - begin - latched_read_dat <= 0; - end - else if (sel_i && ~we_i && memory_ack_i) - begin - for (i=0;i= (access_width_i + alignment)); -assign memory_adr_o = adr_i + dat_shift; -assign access_ack_o = terminal_count && sel_i; - -// This is the watchdog timer -// It runs whenever the memory_sizer is selected for an access, and the -// memory has not yet responded with an ack signal. -always @(posedge clk_i) -begin - if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; - else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1; -end - - -endmodule - - Index: memory_sizer/trunk/b10_safe_12_18_01_single_path.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: memory_sizer/trunk/b10_safe_12_18_01_single_path.zip =================================================================== --- memory_sizer/trunk/b10_safe_12_18_01_single_path.zip (nonexistent) +++ memory_sizer/trunk/b10_safe_12_18_01_single_path.zip (revision 4)
memory_sizer/trunk/b10_safe_12_18_01_single_path.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: memory_sizer/trunk/memory_sizer.v =================================================================== --- memory_sizer/trunk/memory_sizer.v (nonexistent) +++ memory_sizer/trunk/memory_sizer.v (revision 4) @@ -0,0 +1,444 @@ +//---------------------------------------------------------------------------- +// Wishbone memory_sizer 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 to include scalable +// "byte sized barrel shifter" and byte reversal blocks (the 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 Added file header according to opencores recommendations. +// +// 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 byte + + +module memory_sizer ( + 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 bus +parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes) +parameter ADR_BITS_PP = 32; // # of bits in adr buses +parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected +parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer + + +// I/O declarations +input clk_i; // Memory sub-system clock input +input reset_i; // Reset signal for this module +input sel_i; // Enables watchdog timer, activates memory_sizer +input memory_ack_i; // Ack from memory (delay for wait states) +input memory_has_be_i; // Indicates memory at current address has byte enables +input [LOG2_N_PP:0] memory_width_i; // Width code of memory +input [LOG2_N_PP:0] access_width_i; // Width code of access request +input access_big_endian_i; // 0=little endian, 1=big endian +input [ADR_BITS_PP-1:0] adr_i; // Address bus input +input we_i; // type of access +inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus +inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory +output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory +output memory_we_o; // we to memory +output [N_PP-1:0] memory_be_o; // byte enables to memory +output access_ack_o; // shows that access is completed +output exception_be_o; // exception for write to non-byte-enabled memory +output exception_watchdog_o; // exception for memory_ack_i watch dog timeout + +// Internal signal declarations +wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing +wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading +wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" +wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads. +wire [N_PP-1:0] latch_be_big_endian; +wire [LOG2_N_PP-1:0] latch_be_adjust; +wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit + // is for terminal count compare.) +wire [LOG2_N_PP-1:0] alignment; // shows aligment of access +wire terminal_count; // signifies last store cycle +wire [`BYTE_SIZE*N_PP-1:0] steer_dat_i; // data input to byte steering logic +wire [`BYTE_SIZE*N_PP-1:0] revrs_dat_i; // data input to byte reversing logic + +reg [LOG2_N_PP-1:0] byte_mux_select; // selects which bytes to transfer +reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables +reg [`BYTE_SIZE*N_PP-1:0] revrs_dat_o; // data out from byte reversing logic +reg [`BYTE_SIZE*N_PP-1:0] steer_dat_o; // data out from byte steering logic +reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing) +reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass + + +reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count; + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +// Functions & Tasks +//-------------------------------------------------------------------------- + +function [`BYTE_SIZE*N_PP-1:0] byte_reversal; + input [`BYTE_SIZE*N_PP-1:0] din; + integer k; + begin + for (k=0; k> dat_shift) + :{N_PP{1'b1}}; + // (memory byte enables are all high for reads!) + +// For big_endian reads, the latch byte enables (and indeed the data also) +// are shifted using a special mapping, which causes the data to appear at +// the opposite end of the "read_data" bus. +assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment); +assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1); +assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust; +assign latch_be = (access_big_endian_i)?latch_be_big_endian + :latch_be_lil_endian; + +// Exceptions +assign exception_be_o = (alignment != 0) && ~memory_has_be_i; +assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP); + +// Pass signals to memory +assign memory_we_o = we_i; + + +// Enable the data bus outputs in each direction +assign dat_io = (sel_i && ~we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; +assign memory_dat_io = (sel_i && we_i)?steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; + +// Decide which bus supplies the byte reversing logic +// (One could just use a single mux here instead of the tri-state buffers. +// in fact, the synthesis tool might decide to change the tri-state buffers +// into simple 2:1 muxes...) +assign revrs_dat_i = (~we_i)?read_dat:{`BYTE_SIZE*N_PP{1'bZ}}; +assign revrs_dat_i = (we_i)?dat_io:{`BYTE_SIZE*N_PP{1'bZ}}; + + +// Decide which bus supplies the byte steering logic +// (One could just use a single mux here instead of the tri-state buffers. +// in fact, the synthesis tool might decide to change the tri-state buffers +// into simple 2:1 muxes...) +assign steer_dat_i = (~we_i)?memory_dat_io:{`BYTE_SIZE*N_PP{1'bZ}}; +assign steer_dat_i = (we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; + + +// This logic latches the data bytes which are read during the first cycles +// of an access. During the final cycle of the access, then "terminal_count" +// is asserted by the counting logic, which causes the latches which are +// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes. +// This means that for single cycle accesses, the data will flow directly +// around the latches and an extra clock cycle will not be needed in order +// to latch the data... +always @(posedge clk_i) +begin: BYTE_LATCHES + integer i; + + if (reset_i || terminal_count || ~sel_i) + begin + latched_read_dat <= 0; + end + else if (sel_i && ~we_i && memory_ack_i) + begin + for (i=0;i> `BYTE_SIZE*byte_mux_select) + |(steer_dat_i << `BYTE_SIZE*(N_PP-byte_mux_select)) + ); +end + + +// This is the counting logic. +// It is implemented using "count_next" in order to detect when +// the last cycle is being performed, which is when the "next" count +// equals or exceeds the total size of the access requested in bytes. +// (Using the "next" approach avoids issues relating to different +// memory sizes!) +always @(posedge clk_i) +begin + if (reset_i || terminal_count || ~sel_i) dat_shift <= 0; + else if (memory_ack_i) dat_shift <= dat_shift_next; +end + +assign dat_shift_next = dat_shift + memory_width_i; +assign terminal_count = (dat_shift_next >= (access_width_i + alignment)); +assign memory_adr_o = adr_i + dat_shift; +assign access_ack_o = terminal_count && sel_i; + +// This is the watchdog timer +// It runs whenever the memory_sizer is selected for an access, and the +// memory has not yet responded with an ack signal. +always @(posedge clk_i) +begin + if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; + else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1; +end + + +endmodule + + Index: memory_sizer/trunk/memory_sizer_dual_path.v =================================================================== --- memory_sizer/trunk/memory_sizer_dual_path.v (nonexistent) +++ memory_sizer/trunk/memory_sizer_dual_path.v (revision 4) @@ -0,0 +1,477 @@ +//---------------------------------------------------------------------------- +// 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 byte + + +module 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 bus +parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes) +parameter ADR_BITS_PP = 32; // # of bits in adr buses +parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected +parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer + + +// I/O declarations +input clk_i; // Memory sub-system clock input +input reset_i; // Reset signal for this module +input sel_i; // Enables watchdog timer, activates memory_sizer +input memory_ack_i; // Ack from memory (delay for wait states) +input memory_has_be_i; // Indicates memory at current address has byte enables +input [LOG2_N_PP:0] memory_width_i; // Width code of memory +input [LOG2_N_PP:0] access_width_i; // Width code of access request +input access_big_endian_i; // 0=little endian, 1=big endian +input [ADR_BITS_PP-1:0] adr_i; // Address bus input +input we_i; // type of access +inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus +inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory +output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory +output memory_we_o; // we to memory +output [N_PP-1:0] memory_be_o; // byte enables to memory +output access_ack_o; // shows that access is completed +output exception_be_o; // exception for write to non-byte-enabled memory +output exception_watchdog_o; // exception for memory_ack_i watch dog timeout + +// Internal signal declarations +wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing +wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading +wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" +wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads. +wire [N_PP-1:0] latch_be_big_endian; +wire [LOG2_N_PP-1:0] latch_be_adjust; +wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit + // is for terminal count compare.) +wire [LOG2_N_PP-1:0] alignment; // shows aligment of access +wire terminal_count; // signifies last store cycle + +reg [LOG2_N_PP-1:0] rd_byte_mux_select; // selects which bytes to transfer +reg [LOG2_N_PP-1:0] wr_byte_mux_select; // selects which bytes to transfer +reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables +reg [`BYTE_SIZE*N_PP-1:0] wr_steer_dat_o; // data from byte steering logic +reg [`BYTE_SIZE*N_PP-1:0] wr_revrs_dat_o; // data from byte reversing logic +reg [`BYTE_SIZE*N_PP-1:0] rd_revrs_dat_o; // data from byte reversing logic +reg [`BYTE_SIZE*N_PP-1:0] rd_steer_dat_o; // data from byte steering logic +reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing) +reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass + + +reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count; + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +// Functions & Tasks +//-------------------------------------------------------------------------- + +function [`BYTE_SIZE*N_PP-1:0] byte_reversal; + input [`BYTE_SIZE*N_PP-1:0] din; + integer k; + begin + for (k=0; k> dat_shift) + :{N_PP{1'b1}}; + // (memory byte enables are all high for reads!) + +// For big_endian reads, the latch byte enables (and indeed the data also) +// are shifted using a special mapping, which causes the data to appear at +// the opposite end of the "read_data" bus. +assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment); +assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1); +assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust; +assign latch_be = (access_big_endian_i)?latch_be_big_endian + :latch_be_lil_endian; + +// Exceptions +assign exception_be_o = (alignment != 0) && ~memory_has_be_i; +assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP); + +// Pass signals to memory +assign memory_we_o = we_i; + + +// Enable the data bus outputs in each direction +assign dat_io = (sel_i && ~we_i)?rd_revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; +assign memory_dat_io = (sel_i && we_i)?wr_steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; + + + +// THIS LOGIC IS FOR THE WRITING PATH +//------------------------------------- +// Byte reversal logic +always @( + dat_io or + access_big_endian_i + ) +begin + // Reverse the bytes of the data bus, if needed + if (access_big_endian_i) wr_revrs_dat_o <= byte_reversal(dat_io); + else wr_revrs_dat_o <= dat_io; +end + + +// Steering logic +always @( + wr_revrs_dat_o or + dat_shift or + alignment or + we_i or + access_width_i or + access_big_endian_i + ) +begin + // If bytes are reversed, an extra "bit inversion mask" is applied + // to reflect a new mapping which is correct for reversed bytes. + if (access_big_endian_i) + wr_byte_mux_select <= (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)) + - alignment; + else wr_byte_mux_select <= dat_shift - alignment; + + // Rotate the data bus (byte-sized barrel shifter!) + wr_steer_dat_o <= ( + (wr_revrs_dat_o >> `BYTE_SIZE*wr_byte_mux_select) + |(wr_revrs_dat_o << `BYTE_SIZE*(N_PP-wr_byte_mux_select)) + ); +end + + +// THIS LOGIC IS FOR THE READING PATH +//------------------------------------- + +// Steering logic +always @( + memory_dat_io or + dat_shift or + alignment or + we_i or + access_width_i or + access_big_endian_i + ) +begin + // For reads, negate the shift amount + if (access_big_endian_i) + rd_byte_mux_select <= alignment + - (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)); + else rd_byte_mux_select <= alignment - dat_shift; + + // Rotate the data bus (byte-sized barrel shifter!) + rd_steer_dat_o <= ( + (memory_dat_io >> `BYTE_SIZE*rd_byte_mux_select) + |(memory_dat_io << `BYTE_SIZE*(N_PP-rd_byte_mux_select)) + ); +end + + +// This logic latches the data bytes which are read during the first cycles +// of an access. During the final cycle of the access, then "terminal_count" +// is asserted by the counting logic, which causes the latches which are +// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes. +// This means that for single cycle accesses, the data will flow directly +// around the latches and an extra clock cycle will not be needed in order +// to latch the data... +always @(posedge clk_i) +begin: BYTE_LATCHES + integer i; + + if (reset_i || terminal_count || ~sel_i) + begin + latched_read_dat <= 0; + end + else if (sel_i && ~we_i && memory_ack_i) + begin + for (i=0;i= (access_width_i + alignment)); +assign memory_adr_o = adr_i + dat_shift; +assign access_ack_o = terminal_count && sel_i; + +// This is the watchdog timer +// It runs whenever the memory_sizer is selected for an access, and the +// memory has not yet responded with an ack signal. +always @(posedge clk_i) +begin + if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; + else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1; +end + + +endmodule + + Index: memory_sizer/trunk/b10_safe_12_18_01_dual_path.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: memory_sizer/trunk/b10_safe_12_18_01_dual_path.zip =================================================================== --- memory_sizer/trunk/b10_safe_12_18_01_dual_path.zip (nonexistent) +++ memory_sizer/trunk/b10_safe_12_18_01_dual_path.zip (revision 4)
memory_sizer/trunk/b10_safe_12_18_01_dual_path.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: memory_sizer/trunk =================================================================== --- memory_sizer/trunk (nonexistent) +++ memory_sizer/trunk (revision 4)
memory_sizer/trunk Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: memory_sizer/web_uploads =================================================================== --- memory_sizer/web_uploads (nonexistent) +++ memory_sizer/web_uploads (revision 4)
memory_sizer/web_uploads Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: memory_sizer/branches =================================================================== --- memory_sizer/branches (nonexistent) +++ memory_sizer/branches (revision 4)
memory_sizer/branches Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: memory_sizer/tags/V001/b10_safe_12_18_01_single_path.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: memory_sizer/tags/V001/b10_safe_12_18_01_single_path.zip =================================================================== --- memory_sizer/tags/V001/b10_safe_12_18_01_single_path.zip (nonexistent) +++ memory_sizer/tags/V001/b10_safe_12_18_01_single_path.zip (revision 4)
memory_sizer/tags/V001/b10_safe_12_18_01_single_path.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: memory_sizer/tags/V001/memory_sizer.v =================================================================== --- memory_sizer/tags/V001/memory_sizer.v (nonexistent) +++ memory_sizer/tags/V001/memory_sizer.v (revision 4) @@ -0,0 +1,444 @@ +//---------------------------------------------------------------------------- +// Wishbone memory_sizer 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 to include scalable +// "byte sized barrel shifter" and byte reversal blocks (the 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 Added file header according to opencores recommendations. +// +// 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 byte + + +module memory_sizer ( + 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 bus +parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes) +parameter ADR_BITS_PP = 32; // # of bits in adr buses +parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected +parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer + + +// I/O declarations +input clk_i; // Memory sub-system clock input +input reset_i; // Reset signal for this module +input sel_i; // Enables watchdog timer, activates memory_sizer +input memory_ack_i; // Ack from memory (delay for wait states) +input memory_has_be_i; // Indicates memory at current address has byte enables +input [LOG2_N_PP:0] memory_width_i; // Width code of memory +input [LOG2_N_PP:0] access_width_i; // Width code of access request +input access_big_endian_i; // 0=little endian, 1=big endian +input [ADR_BITS_PP-1:0] adr_i; // Address bus input +input we_i; // type of access +inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus +inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory +output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory +output memory_we_o; // we to memory +output [N_PP-1:0] memory_be_o; // byte enables to memory +output access_ack_o; // shows that access is completed +output exception_be_o; // exception for write to non-byte-enabled memory +output exception_watchdog_o; // exception for memory_ack_i watch dog timeout + +// Internal signal declarations +wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing +wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading +wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" +wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads. +wire [N_PP-1:0] latch_be_big_endian; +wire [LOG2_N_PP-1:0] latch_be_adjust; +wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit + // is for terminal count compare.) +wire [LOG2_N_PP-1:0] alignment; // shows aligment of access +wire terminal_count; // signifies last store cycle +wire [`BYTE_SIZE*N_PP-1:0] steer_dat_i; // data input to byte steering logic +wire [`BYTE_SIZE*N_PP-1:0] revrs_dat_i; // data input to byte reversing logic + +reg [LOG2_N_PP-1:0] byte_mux_select; // selects which bytes to transfer +reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables +reg [`BYTE_SIZE*N_PP-1:0] revrs_dat_o; // data out from byte reversing logic +reg [`BYTE_SIZE*N_PP-1:0] steer_dat_o; // data out from byte steering logic +reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing) +reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass + + +reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count; + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +// Functions & Tasks +//-------------------------------------------------------------------------- + +function [`BYTE_SIZE*N_PP-1:0] byte_reversal; + input [`BYTE_SIZE*N_PP-1:0] din; + integer k; + begin + for (k=0; k> dat_shift) + :{N_PP{1'b1}}; + // (memory byte enables are all high for reads!) + +// For big_endian reads, the latch byte enables (and indeed the data also) +// are shifted using a special mapping, which causes the data to appear at +// the opposite end of the "read_data" bus. +assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment); +assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1); +assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust; +assign latch_be = (access_big_endian_i)?latch_be_big_endian + :latch_be_lil_endian; + +// Exceptions +assign exception_be_o = (alignment != 0) && ~memory_has_be_i; +assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP); + +// Pass signals to memory +assign memory_we_o = we_i; + + +// Enable the data bus outputs in each direction +assign dat_io = (sel_i && ~we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; +assign memory_dat_io = (sel_i && we_i)?steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; + +// Decide which bus supplies the byte reversing logic +// (One could just use a single mux here instead of the tri-state buffers. +// in fact, the synthesis tool might decide to change the tri-state buffers +// into simple 2:1 muxes...) +assign revrs_dat_i = (~we_i)?read_dat:{`BYTE_SIZE*N_PP{1'bZ}}; +assign revrs_dat_i = (we_i)?dat_io:{`BYTE_SIZE*N_PP{1'bZ}}; + + +// Decide which bus supplies the byte steering logic +// (One could just use a single mux here instead of the tri-state buffers. +// in fact, the synthesis tool might decide to change the tri-state buffers +// into simple 2:1 muxes...) +assign steer_dat_i = (~we_i)?memory_dat_io:{`BYTE_SIZE*N_PP{1'bZ}}; +assign steer_dat_i = (we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; + + +// This logic latches the data bytes which are read during the first cycles +// of an access. During the final cycle of the access, then "terminal_count" +// is asserted by the counting logic, which causes the latches which are +// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes. +// This means that for single cycle accesses, the data will flow directly +// around the latches and an extra clock cycle will not be needed in order +// to latch the data... +always @(posedge clk_i) +begin: BYTE_LATCHES + integer i; + + if (reset_i || terminal_count || ~sel_i) + begin + latched_read_dat <= 0; + end + else if (sel_i && ~we_i && memory_ack_i) + begin + for (i=0;i> `BYTE_SIZE*byte_mux_select) + |(steer_dat_i << `BYTE_SIZE*(N_PP-byte_mux_select)) + ); +end + + +// This is the counting logic. +// It is implemented using "count_next" in order to detect when +// the last cycle is being performed, which is when the "next" count +// equals or exceeds the total size of the access requested in bytes. +// (Using the "next" approach avoids issues relating to different +// memory sizes!) +always @(posedge clk_i) +begin + if (reset_i || terminal_count || ~sel_i) dat_shift <= 0; + else if (memory_ack_i) dat_shift <= dat_shift_next; +end + +assign dat_shift_next = dat_shift + memory_width_i; +assign terminal_count = (dat_shift_next >= (access_width_i + alignment)); +assign memory_adr_o = adr_i + dat_shift; +assign access_ack_o = terminal_count && sel_i; + +// This is the watchdog timer +// It runs whenever the memory_sizer is selected for an access, and the +// memory has not yet responded with an ack signal. +always @(posedge clk_i) +begin + if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; + else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1; +end + + +endmodule + + Index: memory_sizer/tags/V001/memory_sizer_dual_path.v =================================================================== --- memory_sizer/tags/V001/memory_sizer_dual_path.v (nonexistent) +++ memory_sizer/tags/V001/memory_sizer_dual_path.v (revision 4) @@ -0,0 +1,477 @@ +//---------------------------------------------------------------------------- +// 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 byte + + +module 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 bus +parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes) +parameter ADR_BITS_PP = 32; // # of bits in adr buses +parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected +parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer + + +// I/O declarations +input clk_i; // Memory sub-system clock input +input reset_i; // Reset signal for this module +input sel_i; // Enables watchdog timer, activates memory_sizer +input memory_ack_i; // Ack from memory (delay for wait states) +input memory_has_be_i; // Indicates memory at current address has byte enables +input [LOG2_N_PP:0] memory_width_i; // Width code of memory +input [LOG2_N_PP:0] access_width_i; // Width code of access request +input access_big_endian_i; // 0=little endian, 1=big endian +input [ADR_BITS_PP-1:0] adr_i; // Address bus input +input we_i; // type of access +inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus +inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory +output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory +output memory_we_o; // we to memory +output [N_PP-1:0] memory_be_o; // byte enables to memory +output access_ack_o; // shows that access is completed +output exception_be_o; // exception for write to non-byte-enabled memory +output exception_watchdog_o; // exception for memory_ack_i watch dog timeout + +// Internal signal declarations +wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing +wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading +wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" +wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads. +wire [N_PP-1:0] latch_be_big_endian; +wire [LOG2_N_PP-1:0] latch_be_adjust; +wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit + // is for terminal count compare.) +wire [LOG2_N_PP-1:0] alignment; // shows aligment of access +wire terminal_count; // signifies last store cycle + +reg [LOG2_N_PP-1:0] rd_byte_mux_select; // selects which bytes to transfer +reg [LOG2_N_PP-1:0] wr_byte_mux_select; // selects which bytes to transfer +reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables +reg [`BYTE_SIZE*N_PP-1:0] wr_steer_dat_o; // data from byte steering logic +reg [`BYTE_SIZE*N_PP-1:0] wr_revrs_dat_o; // data from byte reversing logic +reg [`BYTE_SIZE*N_PP-1:0] rd_revrs_dat_o; // data from byte reversing logic +reg [`BYTE_SIZE*N_PP-1:0] rd_steer_dat_o; // data from byte steering logic +reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing) +reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass + + +reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count; + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +// Functions & Tasks +//-------------------------------------------------------------------------- + +function [`BYTE_SIZE*N_PP-1:0] byte_reversal; + input [`BYTE_SIZE*N_PP-1:0] din; + integer k; + begin + for (k=0; k> dat_shift) + :{N_PP{1'b1}}; + // (memory byte enables are all high for reads!) + +// For big_endian reads, the latch byte enables (and indeed the data also) +// are shifted using a special mapping, which causes the data to appear at +// the opposite end of the "read_data" bus. +assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment); +assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1); +assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust; +assign latch_be = (access_big_endian_i)?latch_be_big_endian + :latch_be_lil_endian; + +// Exceptions +assign exception_be_o = (alignment != 0) && ~memory_has_be_i; +assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP); + +// Pass signals to memory +assign memory_we_o = we_i; + + +// Enable the data bus outputs in each direction +assign dat_io = (sel_i && ~we_i)?rd_revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; +assign memory_dat_io = (sel_i && we_i)?wr_steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}}; + + + +// THIS LOGIC IS FOR THE WRITING PATH +//------------------------------------- +// Byte reversal logic +always @( + dat_io or + access_big_endian_i + ) +begin + // Reverse the bytes of the data bus, if needed + if (access_big_endian_i) wr_revrs_dat_o <= byte_reversal(dat_io); + else wr_revrs_dat_o <= dat_io; +end + + +// Steering logic +always @( + wr_revrs_dat_o or + dat_shift or + alignment or + we_i or + access_width_i or + access_big_endian_i + ) +begin + // If bytes are reversed, an extra "bit inversion mask" is applied + // to reflect a new mapping which is correct for reversed bytes. + if (access_big_endian_i) + wr_byte_mux_select <= (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)) + - alignment; + else wr_byte_mux_select <= dat_shift - alignment; + + // Rotate the data bus (byte-sized barrel shifter!) + wr_steer_dat_o <= ( + (wr_revrs_dat_o >> `BYTE_SIZE*wr_byte_mux_select) + |(wr_revrs_dat_o << `BYTE_SIZE*(N_PP-wr_byte_mux_select)) + ); +end + + +// THIS LOGIC IS FOR THE READING PATH +//------------------------------------- + +// Steering logic +always @( + memory_dat_io or + dat_shift or + alignment or + we_i or + access_width_i or + access_big_endian_i + ) +begin + // For reads, negate the shift amount + if (access_big_endian_i) + rd_byte_mux_select <= alignment + - (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)); + else rd_byte_mux_select <= alignment - dat_shift; + + // Rotate the data bus (byte-sized barrel shifter!) + rd_steer_dat_o <= ( + (memory_dat_io >> `BYTE_SIZE*rd_byte_mux_select) + |(memory_dat_io << `BYTE_SIZE*(N_PP-rd_byte_mux_select)) + ); +end + + +// This logic latches the data bytes which are read during the first cycles +// of an access. During the final cycle of the access, then "terminal_count" +// is asserted by the counting logic, which causes the latches which are +// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes. +// This means that for single cycle accesses, the data will flow directly +// around the latches and an extra clock cycle will not be needed in order +// to latch the data... +always @(posedge clk_i) +begin: BYTE_LATCHES + integer i; + + if (reset_i || terminal_count || ~sel_i) + begin + latched_read_dat <= 0; + end + else if (sel_i && ~we_i && memory_ack_i) + begin + for (i=0;i= (access_width_i + alignment)); +assign memory_adr_o = adr_i + dat_shift; +assign access_ack_o = terminal_count && sel_i; + +// This is the watchdog timer +// It runs whenever the memory_sizer is selected for an access, and the +// memory has not yet responded with an ack signal. +always @(posedge clk_i) +begin + if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; + else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1; +end + + +endmodule + + Index: memory_sizer/tags/V001/b10_safe_12_18_01_dual_path.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: memory_sizer/tags/V001/b10_safe_12_18_01_dual_path.zip =================================================================== --- memory_sizer/tags/V001/b10_safe_12_18_01_dual_path.zip (nonexistent) +++ memory_sizer/tags/V001/b10_safe_12_18_01_dual_path.zip (revision 4)
memory_sizer/tags/V001/b10_safe_12_18_01_dual_path.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: memory_sizer/tags =================================================================== --- memory_sizer/tags (nonexistent) +++ memory_sizer/tags (revision 4)
memory_sizer/tags Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ##

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.