Update to SDRAM and SoC
@@ -402,13 +402,17 @@ set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBootBRAM.
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBRAM.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/ioctl/ioctl.vhd
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/TCPU/tcpu.vhd
|
||||
set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/sdram.qip
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/SDRAM/sdram.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16_cached.qip
|
||||
set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_top.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_byte_ctrl.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_bit_ctrl.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/wbsdram.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/SDRAM/wbsdram.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT"
|
||||
|
||||
set_global_assignment -name VHDL_INPUT_VERSION VHDL_2008
|
||||
|
||||
@@ -59,13 +59,14 @@ ARCHITECTURE SYN OF clock_50to100 IS
|
||||
SIGNAL sub_wire3 : STD_LOGIC ;
|
||||
SIGNAL sub_wire4 : STD_LOGIC ;
|
||||
SIGNAL sub_wire5 : STD_LOGIC_VECTOR (1 DOWNTO 0);
|
||||
SIGNAL sub_wire6_bv : BIT_VECTOR (0 DOWNTO 0);
|
||||
SIGNAL sub_wire6_bv : BIT_VECTOR (0 DOWNTO 0);
|
||||
SIGNAL sub_wire6 : STD_LOGIC_VECTOR (0 DOWNTO 0);
|
||||
|
||||
|
||||
|
||||
COMPONENT altpll
|
||||
GENERIC (
|
||||
bandwidth_type : STRING;
|
||||
clk0_divide_by : NATURAL;
|
||||
clk0_duty_cycle : NATURAL;
|
||||
clk0_multiply_by : NATURAL;
|
||||
@@ -146,18 +147,19 @@ BEGIN
|
||||
|
||||
altpll_component : altpll
|
||||
GENERIC MAP (
|
||||
bandwidth_type => "AUTO",
|
||||
clk0_divide_by => 1,
|
||||
clk0_duty_cycle => 50,
|
||||
clk0_multiply_by => 2,
|
||||
clk0_phase_shift => "0",
|
||||
clk1_divide_by => 2,
|
||||
clk1_divide_by => 1,
|
||||
clk1_duty_cycle => 50,
|
||||
clk1_multiply_by => 2,
|
||||
clk1_phase_shift => "00",
|
||||
clk1_phase_shift => "-2500 ps",
|
||||
compensate_clock => "CLK0",
|
||||
gate_lock_signal => "NO",
|
||||
inclk0_input_frequency => 20000,
|
||||
intended_device_family => "Cyclone II",
|
||||
intended_device_family => "Cyclone V",
|
||||
invalid_lock_multiplier => 5,
|
||||
lpm_hint => "CBX_MODULE_PREFIX=Clock_50to100",
|
||||
lpm_type => "altpll",
|
||||
|
||||
@@ -455,11 +455,18 @@ set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBootBRAM.
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBootBRAM.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBRAM.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/ioctl/ioctl.vhd
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/TCPU/tcpu.vhd
|
||||
set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/sdram.qip
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/TCPU/tcpu.vhd
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/TCPU/tcpu.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_top.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_byte_ctrl.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_bit_ctrl.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/wbsdram.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/SDRAM/wbsdram.vhd
|
||||
|
||||
@@ -481,11 +481,18 @@ set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBootBRAM.
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBRAM.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/ioctl/ioctl.vhd
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/TCPU/tcpu.vhd
|
||||
set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/sdram.qip
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/SDRAM/sdram.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_top.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_byte_ctrl.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_bit_ctrl.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6_cached.qip
|
||||
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/wbsdram.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/SDRAM/wbsdram.vhd
|
||||
set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT"
|
||||
|
||||
@@ -270,13 +270,17 @@ set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBootBRAM.
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBRAM.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/ioctl/ioctl.vhd
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/TCPU/tcpu.vhd
|
||||
set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/sdram.qip
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/SDRAM/sdram.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_top.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_byte_ctrl.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_bit_ctrl.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/wbsdram.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/SDRAM/wbsdram.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/SRAM/sram.vhd
|
||||
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
|
||||
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
|
||||
@@ -295,4 +299,4 @@ set_global_assignment -name VHDL_SHOW_LMF_MAPPING_MESSAGES OFF
|
||||
|
||||
|
||||
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
# Project-Wide Assignments
|
||||
# ========================
|
||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13
|
||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "23:35:58 SEPTEMBER 01, 2005"
|
||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 17.0.0
|
||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "23:35:58 SEPTEMBER 01, 2017"
|
||||
set_global_assignment -name LAST_QUARTUS_VERSION "17.1.1 Standard Edition"
|
||||
set_global_assignment -name CDF_FILE QMV.cdf
|
||||
|
||||
@@ -42,10 +42,10 @@ set_global_assignment -name TOP_LEVEL_ENTITY QMV_zpu
|
||||
# ==================
|
||||
set_global_assignment -name DEVICE 5CEFA2F23C8
|
||||
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 256
|
||||
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
|
||||
|
||||
# Assembler Assignments
|
||||
# =====================
|
||||
|
||||
set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 7
|
||||
set_global_assignment -name AUTO_RESTART_CONFIGURATION OFF
|
||||
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 484
|
||||
@@ -76,6 +76,7 @@ set_global_assignment -name ENABLE_SIGNALTAP ON
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp
|
||||
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
||||
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
||||
set_global_assignment -name NUM_PARALLEL_PROCESSORS 8
|
||||
|
||||
|
||||
#============================================================
|
||||
@@ -138,25 +139,6 @@ set_location_assignment PIN_AB7 -to SDRAM_DQM[0]
|
||||
set_location_assignment PIN_AB6 -to SDRAM_RAS
|
||||
set_location_assignment PIN_V10 -to SDRAM_DQM[1]
|
||||
set_location_assignment PIN_W9 -to SDRAM_WE
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[0]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[1]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[2]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[3]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[4]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[5]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[6]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[7]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[8]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[9]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[10]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[11]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[12]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[0]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[1]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CAS
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CKE
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CLK
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CS
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[0]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[1]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[2]
|
||||
@@ -173,10 +155,110 @@ set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[12]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[13]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[14]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[15]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[0]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[1]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[2]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[3]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[4]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[5]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[6]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[7]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[8]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[9]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[10]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[11]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[12]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[13]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[14]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[15]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[0]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[1]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[2]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[3]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[4]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[5]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[6]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[7]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[8]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[9]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[10]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[11]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[12]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[13]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[14]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQ[15]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[0]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[1]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[2]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[3]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[4]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[5]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[6]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[7]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[8]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[9]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[10]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[11]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[12]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[13]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[0]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[1]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[2]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[3]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[4]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[5]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[6]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[7]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[8]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[9]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[10]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[11]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[12]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_ADDR[13]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[0]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[1]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[2]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[3]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[4]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[5]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[6]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[7]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[8]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[9]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[10]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[11]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[12]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_ADDR[13]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[0]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[1]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQM[0]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_RAS
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQM[1]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[0]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[1]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQM[0]
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQM[1]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_BA[0]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_BA[1]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQM[0]
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_DQM[1]
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CAS
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_RAS
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_WE
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CS
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CAS
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_RAS
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_WE
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CS
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_CAS
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_RAS
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_WE
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_CS
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CKE
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CLK
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_CKE
|
||||
set_instance_assignment -name SLEW_RATE 0 -to SDRAM_CLK
|
||||
|
||||
#============================================================
|
||||
# GPIO
|
||||
@@ -360,13 +442,17 @@ set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBootBRAM.
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/BRAM/SinglePortBRAM.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/sysbus/ioctl/ioctl.vhd
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/TCPU/tcpu.vhd
|
||||
set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/sdram.qip
|
||||
#set_global_assignment -name VHDL_FILE ../devices/sysbus/SDRAM/sdram.vhd
|
||||
set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/sysbus/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_top.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_byte_ctrl.vhd
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/I2C/i2c_master_bit_ctrl.vhd
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/wbsdram.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/SDRAM/wbsdram.vhd
|
||||
set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/48LC16M16_cached.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6.qip
|
||||
#set_global_assignment -name QIP_FILE ../devices/WishBone/SDRAM/W9864G6_cached.qip
|
||||
set_global_assignment -name VHDL_FILE ../devices/WishBone/SRAM/sram.vhd
|
||||
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
|
||||
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
|
||||
@@ -379,10 +465,7 @@ set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON
|
||||
set_global_assignment -name HDL_MESSAGE_LEVEL LEVEL3
|
||||
set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (VHDL)"
|
||||
set_global_assignment -name EDA_OUTPUT_DATA_FORMAT VHDL -section_id eda_simulation
|
||||
|
||||
set_global_assignment -name VHDL_INPUT_VERSION VHDL_2008
|
||||
set_global_assignment -name VHDL_SHOW_LMF_MAPPING_MESSAGES OFF
|
||||
|
||||
|
||||
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
|
||||
@@ -40,8 +40,8 @@ create_clock -name {clk_50} -period 20.000 -waveform { 0.000 0.500 } [get_ports
|
||||
# Create Generated Clock
|
||||
#**************************************************************
|
||||
|
||||
create_generated_clock -name {SYSCLK} -source [get_pins {mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|vco0ph[0]}] -duty_cycle 50.000 -multiply_by 2 -divide_by 1 -master_clock {clk_50} [get_pins {mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk}]
|
||||
create_generated_clock -name {MEMCLK} -source [get_pins {mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|vco0ph[0]}] -duty_cycle 50.000 -multiply_by 2 -divide_by 2 -phase 0000 -master_clock {clk_50} [get_pins {mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|divclk}]
|
||||
create_generated_clock -name {SYSCLK} -source [get_pins {mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|vco0ph[0]}] -duty_cycle 50.000 -multiply_by 2 -divide_by 1 -phase 000 -master_clock {clk_50} [get_pins {mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk}]
|
||||
create_generated_clock -name {MEMCLK} -source [get_pins {mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|vco0ph[0]}] -duty_cycle 50.000 -multiply_by 2 -divide_by 1 -offset -2500 -master_clock {clk_50} [get_pins {mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|divclk}]
|
||||
|
||||
#**************************************************************
|
||||
# Set Clock Latency
|
||||
|
||||
@@ -36,22 +36,24 @@
|
||||
-- official policies, either expressed or implied, of the ZPU Project.
|
||||
--
|
||||
-- Evo History:
|
||||
-- 181230 v0.1 Initial version created by merging items of the Small, Medium and Flex versions.
|
||||
-- 190328 v0.5 Working with Instruction, Emulation or No Cache with or without seperate instruction
|
||||
-- bus. Runs numerous tests and output same as the Medium CPU. One small issue is running
|
||||
-- without an instruction bus and instruction/emulation cache enabled, the DMIPS value is lower
|
||||
-- that just with instruction bus or emulation bus, seems some clash which reuults in waits states
|
||||
-- slowing the CPU down.
|
||||
-- 191021 v1.0 First release. All variations tested but more work needed on the SDRAM controller to
|
||||
-- make use of burst mode in order to populate the L2 cache in fewer cycles.
|
||||
-- Additional instructions need to be added back in after test and verification, albeit some
|
||||
-- which are sepcific to the Sharp Emulator should be skipped.
|
||||
-- Additional effort needs spending on the Wishbone Error signal to retry the bus transaction,
|
||||
-- currently it just aborts it which is not ideal.
|
||||
-- 191126 v1.1 Bug fixes. When switching off WishBone the CPU wouldnt run.
|
||||
-- 191215 v1.2 Bug fixes. Removed L2 Cache megacore and replaced with inferred equivalent, fixed hardware
|
||||
-- byte/h-word write which was always defaulting to read-update-write, fixed L2 timing with
|
||||
-- external SDRAM, minor tweaks and currently looking at better constraints.
|
||||
-- 181230 v0.1 Initial version created by merging items of the Small, Medium and Flex versions.
|
||||
-- 190328 v0.5 Working with Instruction, Emulation or No Cache with or without seperate instruction
|
||||
-- bus. Runs numerous tests and output same as the Medium CPU. One small issue is running
|
||||
-- without an instruction bus and instruction/emulation cache enabled, the DMIPS value is lower
|
||||
-- than just with instruction bus or emulation bus, seems some clash which reuults in waits states
|
||||
-- slowing the CPU down.
|
||||
-- 191021 v1.0 First release. All variations tested but more work needed on the SDRAM controller to
|
||||
-- make use of burst mode in order to populate the L2 cache in fewer cycles.
|
||||
-- Additional instructions need to be added back in after test and verification, albeit some
|
||||
-- which are specific to the Sharp Emulator should be skipped.
|
||||
-- Additional effort needs spending on the Wishbone Error signal to retry the bus transaction,
|
||||
-- currently it just aborts it which is not ideal.
|
||||
-- 191126 v1.1 Bug fixes. When switching off WishBone the CPU wouldnt run.
|
||||
-- 191215 v1.2 Bug fixes. Removed L2 Cache megacore and replaced with inferred equivalent, fixed hardware
|
||||
-- byte/h-word write which was always defaulting to read-update-write, fixed L2 timing with
|
||||
-- external SDRAM, minor tweaks and currently looking at better constraints.
|
||||
-- 191220 v1.21 Changes to Mult, shifting it from a combination assignment to a clocked assignment to improve
|
||||
-- slack. Small changes made for slack in setup and hold.
|
||||
--
|
||||
|
||||
library ieee;
|
||||
@@ -67,18 +69,22 @@ use work.zpu_pkg.all;
|
||||
--
|
||||
-- Main Memory/IO Bus.
|
||||
-- -------------------
|
||||
-- This bus is used to access all external memory and IO, it can also, via configuration, be used to read instructions from attahed memory.
|
||||
-- This bus is used to access all external memory and IO, it can also, via configuration, be used to read instructions from attached memory.
|
||||
--
|
||||
-- MEM_WRITE_ENABLE - set to '1' for a single cycle to send off a write request.
|
||||
-- MEM_WRITE is valid only while MEM_WRITE_ENABLE='1'.
|
||||
-- MEM_WRITE_BYTE - set to '1' when performing a byte write with data in bits 7-0 of MEM_DATA_OUT
|
||||
-- MEM_DATA_OUT is valid only while MEM_WRITE_ENABLE='1'.
|
||||
-- MEM_WRITE_BYTE - set to '1' when performing a byte write with data in bits 7-0 of MEM_DATA_OUT
|
||||
-- MEM_WRITE_HWORD - set to '1' when performing a half word write with data in bits 15-0 of MEM_DATA_OUT
|
||||
-- MEM_READ_ENABLE - set to '1' for a single cycle to send off a read request.
|
||||
-- MEM_READ_ENABLE - set to '1' for a single cycle to send off a read request. Data is expected on MEM_DATA_IN on next clock rising edge
|
||||
-- unless MEM_BUSY is asserted in which case the data is read on the next clock rising edge after MEM_BUSY is
|
||||
-- de-asserted.
|
||||
--
|
||||
-- MEM_BUSY - It is illegal to send off a read/write request when mem_busy='1'.
|
||||
-- Set to '0' when MEM_READ is valid after a read request.
|
||||
-- If it goes to '1'(busy), it is on the cycle after MEM_READ/writeEnable
|
||||
-- is '1'.
|
||||
-- MEM_BUSY - This signal is used to prolong a read or write cycle, whilst asserted, any read or write cycle is paused as is the
|
||||
-- CPU with signals remaining in same state just prior to MEM_BUSY assetion.
|
||||
-- Set to '0' when MEM_READ is valid after a read request.
|
||||
-- If set to '1'(busy), the current cycle is held until released. For MEM_READ_ENABLE = '1' this means data will be
|
||||
-- latched on clock rising edge following deassertion of MEM_BUSY. For MEM_WRITE_ENABLE, the write transaction is held
|
||||
-- with MEM_WRITE_ENABLE asserted until the cycle following the deassertion of MEM_BUSY.
|
||||
-- MEM_ADDR - address for read/write request
|
||||
-- MEM_DATA_IN - read data. Valid only on the cycle after mem_busy='0' after
|
||||
-- MEM_READ_ENABLE='1' for a single cycle.
|
||||
@@ -128,17 +134,19 @@ use work.zpu_pkg.all;
|
||||
-- Instruction Memory Bus
|
||||
-- ----------------------
|
||||
-- This bus is used for dedicated faster response read only memory containing the code to be run. Using this bus results in faster
|
||||
-- CPU performance. If this bus is not used/disabled, all instructions will be fetched via the main bus.
|
||||
-- CPU performance. If this bus is not used/disabled, all instructions will be fetched via the main bus (System or Wishbone bus).
|
||||
--
|
||||
-- MEM_BUSY_INSN - Memory is busy ('1') so data invalid.
|
||||
-- MEM_DATA_IN_INSN - Instruction data in.
|
||||
-- MEM_ADDR_INSN - Instruction address bus.
|
||||
-- MEM_READ_ENABLE_INSN - Instruction read enable signal (active high).
|
||||
--
|
||||
-- INT_REQ - set to '1' by external logic until interrupts are acknowledged by CPU.
|
||||
-- INT_ACK - set to '1' for 1 clock cycle when the interrupt is acknowledged and processing commences.
|
||||
-- INT_DONE - set to '1' for 1 clock cycle when the interrupt processing is complete
|
||||
-- BREAK - set to '1' when CPU hits BREAK instruction
|
||||
-- INT_REQ - Set to '1' by external logic until interrupts are acknowledged by CPU.
|
||||
-- INT_ACK - Set to '1' for 1 clock cycle when the interrupt is acknowledged and processing commences.
|
||||
-- INT_DONE - Set to '1' for 1 clock cycle when the interrupt processing is complete
|
||||
-- BREAK - Set to '1' when CPU hits a BREAK instruction
|
||||
-- CONTINUE - When the CPU is halted due to a BREAK instruction, this signal, when asserted ('1') forces the CPU to commence
|
||||
-- processing of the instruction following the BREAK instruction.
|
||||
-- DEBUG_TXD - Serial output of runtime debug data if enabled.
|
||||
|
||||
entity zpu_core_evo is
|
||||
@@ -306,6 +314,7 @@ architecture behave of zpu_core_evo is
|
||||
type StateType is
|
||||
(
|
||||
State_Div2,
|
||||
State_Mult2,
|
||||
State_Execute,
|
||||
State_FiAdd2,
|
||||
State_FiDiv2,
|
||||
@@ -353,8 +362,7 @@ architecture behave of zpu_core_evo is
|
||||
MemXact_WriteByteToAddr,
|
||||
MemXact_WriteByteToAddr2,
|
||||
MemXact_WriteHWordToAddr,
|
||||
MemXact_WriteHWordToAddr2,
|
||||
MemXact_Write
|
||||
MemXact_WriteHWordToAddr2
|
||||
);
|
||||
|
||||
-- Memory transaction processing commands. These states (commands) are the actions which the MTP can process.
|
||||
@@ -423,6 +431,10 @@ architecture behave of zpu_core_evo is
|
||||
signal pc : unsigned(ADDR_BIT_RANGE); -- Current program location being executed.
|
||||
signal pcLast : unsigned(ADDR_BIT_RANGE); -- Last program location executed.
|
||||
signal incPC : unsigned(ADDR_BIT_RANGE); -- Next program location to be executed.
|
||||
signal incIncPC : unsigned(ADDR_BIT_RANGE); -- Next +2 program location to be executed.
|
||||
signal inc3PC : unsigned(ADDR_BIT_RANGE); -- Next +3 program location to be executed.
|
||||
signal inc4PC : unsigned(ADDR_BIT_RANGE); -- Next +4 program location to be executed.
|
||||
signal inc5PC : unsigned(ADDR_BIT_RANGE); -- Next +5 program location to be executed.
|
||||
signal sp : unsigned(ADDR_32BIT_RANGE); -- Current stack pointer.
|
||||
signal incSp : unsigned(ADDR_32BIT_RANGE); -- Stack pointer when 1 value is popped.
|
||||
signal incIncSp : unsigned(ADDR_32BIT_RANGE); -- Stack pointer when 2 values are popped.
|
||||
@@ -437,8 +449,9 @@ architecture behave of zpu_core_evo is
|
||||
signal divRemainder : unsigned(WORD_32BIT_RANGE);
|
||||
signal divStart : std_logic;
|
||||
signal divComplete : std_logic;
|
||||
signal quotientFractional : integer range 0 to 15 := 15; -- Fractional component size of a fixed point value.
|
||||
signal divQuotientFractional : integer range 0 to 15 := 15; -- Fractional component size for the divider as it can be changed dynamically for integer division.
|
||||
signal quotientFractional : integer range 0 to 15; -- Fractional component size of a fixed point value.
|
||||
signal divQuotientFractional : integer range 0 to 15; -- Fractional component size for the divider as it can be changed dynamically for integer division.
|
||||
signal multResult : unsigned(wordSize*2-1 downto 0); -- Result after internal multiplication.
|
||||
signal state : StateType;
|
||||
signal fpAddResult : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal fpMultResult : std_logic_vector(WORD_32BIT_RANGE);
|
||||
@@ -457,8 +470,9 @@ architecture behave of zpu_core_evo is
|
||||
|
||||
-- Interrupt procesing.
|
||||
--
|
||||
signal inInterrupt : std_logic;
|
||||
signal interruptSuspendedAddr : unsigned(ADDR_BIT_RANGE);
|
||||
signal intTriggered : std_logic; -- Flag to indicate an interrupt has been requested, reset when interrupt processing starts.
|
||||
signal inInterrupt : std_logic; -- Flag to indicate that the CPU is currently inside an interrupt processing block.
|
||||
signal interruptSuspendedAddr : unsigned(ADDR_BIT_RANGE); -- Address that was interrupted by the interrupt, used to return processing when interrupt complete.
|
||||
|
||||
-- Instruction storage, decoding and processing.
|
||||
--
|
||||
@@ -467,6 +481,7 @@ architecture behave of zpu_core_evo is
|
||||
signal l1State : Level1CacheStateType; -- Current state of the L1 Cache decode and populate machine.
|
||||
|
||||
-- Cache L1 specific signals.
|
||||
--
|
||||
signal cacheL1 : InsnL1Array; -- Level 1 cache, implemented as registers to gain random access for instruction lookahead optimisation and instruction set extension.
|
||||
signal cacheL1StartAddr : unsigned(ADDR_BIT_RANGE); -- Absolute address of first instruction in cache.
|
||||
signal cacheL1FetchIdx : unsigned(ADDR_BIT_RANGE); -- Index into L1 cache decoded instructions will be placed.
|
||||
@@ -478,6 +493,7 @@ architecture behave of zpu_core_evo is
|
||||
attribute ramstyle of cacheL1 : signal is "logic";
|
||||
|
||||
-- Cache L2 (primary) specific signals.
|
||||
--
|
||||
signal cacheL2FetchIdx : unsigned(ADDR_BIT_RANGE); -- Location in memory being read by the decoder for storage into cache.
|
||||
signal cacheL2StartAddr : unsigned(ADDR_BIT_RANGE); -- The actual program address stored in the first cache location.
|
||||
signal cacheL2Active : std_logic; -- A flag to indicate when the L2 cache is in use.
|
||||
@@ -519,13 +535,12 @@ architecture behave of zpu_core_evo is
|
||||
signal debugReady : std_logic; -- Flag to indicate serializer fsm is busy (0) or available (1).
|
||||
|
||||
---------------------------------------------
|
||||
-- Functions
|
||||
-- Functions specific to the CPU core.
|
||||
---------------------------------------------
|
||||
|
||||
begin
|
||||
-- If the wishbone interface is enabled, assign permanent connections.
|
||||
WB_INIT: if IMPL_USE_WB_BUS = true generate
|
||||
--WB_CLK_I <= open;
|
||||
ZPURESET <= RESET or WB_RST_I;
|
||||
else generate
|
||||
ZPURESET <= RESET;
|
||||
@@ -535,35 +550,8 @@ begin
|
||||
-- Cache storage.
|
||||
---------------------------------------------
|
||||
|
||||
-- Level 2 cache is instantiated rather than inferred. In Altera, numerous attempts failed at describing a cache with 1 write and 2 reads for inferrence
|
||||
-- hence resorting to instantiating a defined IP component.
|
||||
-- NB TODO: This needs to be split into a byte addressable IP so that L2 Cache Write Thru can work at byte/half-word level to increase througput.
|
||||
--CACHEL2 : dpram
|
||||
-- generic map (
|
||||
-- init_file => "",
|
||||
-- widthad_a => MAX_L2CACHE_BITS-2,
|
||||
-- width_a => wordSize,
|
||||
-- widthad_b => MAX_L2CACHE_BITS-2,
|
||||
-- width_b => wordSize,
|
||||
-- outdata_reg_a => "UNREGISTERED",
|
||||
-- outdata_reg_b => "UNREGISTERED"
|
||||
-- )
|
||||
-- port map (
|
||||
-- clock_a => CLK,
|
||||
-- clocken_a => '1',
|
||||
-- address_a => std_logic_vector(cacheL2WriteAddr),
|
||||
-- data_a => cacheL2WriteData,
|
||||
-- wren_a => cacheL2Write,
|
||||
-- q_a => open,
|
||||
-- Level 2 cache inferred with byte level write.
|
||||
--
|
||||
-- clock_b => CLK,
|
||||
-- clocken_b => '1',
|
||||
-- address_b => std_logic_vector(cacheL2Mux2Addr),
|
||||
-- data_b => (others => '0'),
|
||||
-- wren_b => '0',
|
||||
-- q_b => cacheL2Word
|
||||
-- );
|
||||
|
||||
CACHEL2 : work.evo_L2cache
|
||||
generic map (
|
||||
addrbits => MAX_L2CACHE_BITS
|
||||
@@ -766,9 +754,9 @@ begin
|
||||
MEM_ADDR(ADDR_32BIT_RANGE) <= std_logic_vector(cacheL2FetchIdx(ADDR_32BIT_RANGE));
|
||||
MEM_ADDR(minAddrBit-1 downto 0) <= (others => '0');
|
||||
MEM_READ_ENABLE <= '1';
|
||||
mxHoldCycles <= 1;
|
||||
end if;
|
||||
cacheL2WriteAddr <= cacheL2FetchIdx(L2CACHE_BIT_RANGE);
|
||||
mxHoldCycles <= 1;
|
||||
mxState <= MemXact_OpcodeFetch;
|
||||
|
||||
-- If there is an item on the queue and the memory system isnt busy from a previous operation, process
|
||||
@@ -1170,15 +1158,17 @@ begin
|
||||
end if;
|
||||
|
||||
when MemXact_WriteByteToAddr2 =>
|
||||
WB_ADR_O(ADDR_32BIT_RANGE) <= mxFifo(to_integer(mxFifoReadIdx)).addr(ADDR_32BIT_RANGE);
|
||||
WB_ADR_O(minAddrBit-1 downto 0) <= (others => '0');
|
||||
WB_WE_O <= '1';
|
||||
WB_CYC_O <= '1';
|
||||
WB_STB_O <= '1';
|
||||
WB_SEL_O <= "1111";
|
||||
wbXactActive <= '1';
|
||||
mxFifoReadIdx <= mxFifoReadIdx + 1;
|
||||
mxState <= MemXact_Idle;
|
||||
if IMPL_USE_WB_BUS = true then
|
||||
WB_ADR_O(ADDR_32BIT_RANGE) <= mxFifo(to_integer(mxFifoReadIdx)).addr(ADDR_32BIT_RANGE);
|
||||
WB_ADR_O(minAddrBit-1 downto 0) <= (others => '0');
|
||||
WB_WE_O <= '1';
|
||||
WB_CYC_O <= '1';
|
||||
WB_STB_O <= '1';
|
||||
WB_SEL_O <= "1111";
|
||||
wbXactActive <= '1';
|
||||
mxFifoReadIdx <= mxFifoReadIdx + 1;
|
||||
mxState <= MemXact_Idle;
|
||||
end if;
|
||||
|
||||
when MemXact_WriteHWordToAddr =>
|
||||
if IMPL_USE_WB_BUS = true and wbXactActive = '1' then
|
||||
@@ -1206,18 +1196,17 @@ begin
|
||||
end if;
|
||||
|
||||
when MemXact_WriteHWordToAddr2 =>
|
||||
WB_ADR_O(ADDR_32BIT_RANGE) <= mxFifo(to_integer(mxFifoReadIdx)).addr(ADDR_32BIT_RANGE);
|
||||
WB_ADR_O(minAddrBit-1 downto 0) <= (others => '0');
|
||||
WB_WE_O <= '1';
|
||||
WB_CYC_O <= '1';
|
||||
WB_STB_O <= '1';
|
||||
WB_SEL_O <= "1111";
|
||||
wbXactActive <= '1';
|
||||
mxFifoReadIdx <= mxFifoReadIdx + 1;
|
||||
mxState <= MemXact_Idle;
|
||||
|
||||
when MemXact_Write =>
|
||||
mxState <= MemXact_Idle;
|
||||
if IMPL_USE_WB_BUS = true then
|
||||
WB_ADR_O(ADDR_32BIT_RANGE) <= mxFifo(to_integer(mxFifoReadIdx)).addr(ADDR_32BIT_RANGE);
|
||||
WB_ADR_O(minAddrBit-1 downto 0) <= (others => '0');
|
||||
WB_WE_O <= '1';
|
||||
WB_CYC_O <= '1';
|
||||
WB_STB_O <= '1';
|
||||
WB_SEL_O <= "1111";
|
||||
wbXactActive <= '1';
|
||||
mxFifoReadIdx <= mxFifoReadIdx + 1;
|
||||
mxState <= MemXact_Idle;
|
||||
end if;
|
||||
|
||||
when others =>
|
||||
end case;
|
||||
@@ -1490,7 +1479,6 @@ begin
|
||||
variable tSpOffset : unsigned(4 downto 0);
|
||||
variable tIdx : integer range 0 to 3;
|
||||
variable tInsnExec : std_logic;
|
||||
variable tMultResult : unsigned(wordSize*2-1 downto 0);
|
||||
variable tShiftCnt : integer range 0 to 31;
|
||||
begin
|
||||
------------------------
|
||||
@@ -1503,6 +1491,10 @@ begin
|
||||
incIncSp <= sp + 2;
|
||||
decSp <= sp - 1;
|
||||
incPC <= pc + 1;
|
||||
incIncPC <= pc + 2;
|
||||
inc3PC <= pc + 3;
|
||||
inc4PC <= pc + 4;
|
||||
inc5PC <= pc + 5;
|
||||
|
||||
------------------------
|
||||
-- ASYNCHRONOUS RESET --
|
||||
@@ -1519,14 +1511,11 @@ begin
|
||||
pcLast <= to_unsigned(RESET_ADDR_CPU, pc'LENGTH);
|
||||
idimFlag <= '0';
|
||||
inInterrupt <= '0';
|
||||
interruptSuspendedAddr <= (others => '0');
|
||||
mxFifoWriteIdx <= (others => '0');
|
||||
interruptSuspendedAddr <= (others => '0');
|
||||
TOS <= ((others => '0'), '0');
|
||||
NOS <= ((others => '0'), '0');
|
||||
--
|
||||
if IMPL_MULT = true then
|
||||
tMultResult := (others => DontCareValue);
|
||||
end if;
|
||||
if IMPL_DIV = true or IMPL_FIDIV32 = true or IMPL_MOD = true then
|
||||
divStart <= '0';
|
||||
divQuotientFractional <= 0;
|
||||
@@ -1554,7 +1543,7 @@ begin
|
||||
debugReady <= DontCareValue;
|
||||
debugOutputOnce <= DontCareValue;
|
||||
end if;
|
||||
|
||||
|
||||
------------------------
|
||||
-- FALLING CLOCK EDGE --
|
||||
------------------------
|
||||
@@ -1600,11 +1589,6 @@ begin
|
||||
debugLoad <= '0';
|
||||
end if;
|
||||
|
||||
-- Multiply unconditionally the TOS and NOS to save time obtaining result.
|
||||
if IMPL_MULT = true then
|
||||
tMultResult := muxTOS.word * muxNOS.word;
|
||||
end if;
|
||||
|
||||
-- Division start is only 1 clock width wide.
|
||||
if IMPL_DIV = true or IMPL_FIDIV32 = true or IMPL_MOD = true then
|
||||
divStart <= '0';
|
||||
@@ -1614,6 +1598,9 @@ begin
|
||||
-- If interrupt is active, we only clear the interrupt state once the PC is reset to the address which was suspended after the
|
||||
-- interrupt, this prevents recursive interrupt triggers, desirable in cetain circumstances but not for this current design.
|
||||
--
|
||||
if (INT_REQ = '1' or (IMPL_USE_WB_BUS = true and WB_INTA_I = '1')) and intTriggered = '0' then
|
||||
intTriggered <= '1';
|
||||
end if;
|
||||
INT_ACK <= '0'; -- Reset interrupt acknowledge if set, width is 1 clock only.
|
||||
INT_DONE <= '0'; -- Reset interrupt done if set, width is 1 clock only.
|
||||
if inInterrupt = '1' and pc(ADDR_BIT_RANGE) = interruptSuspendedAddr(ADDR_BIT_RANGE) then
|
||||
@@ -1675,11 +1662,12 @@ begin
|
||||
end if;
|
||||
|
||||
-- Act immediately if an interrupt has occurred. Do not recurse into ISR while interrupt line is active
|
||||
elsif (INT_REQ = '1' or (IMPL_USE_WB_BUS = true and WB_INTA_I = '1')) and inInterrupt = '0' and idimFlag = '0' then
|
||||
elsif intTriggered = '1' and inInterrupt = '0' and idimFlag = '0' then
|
||||
|
||||
-- We have to wait for TOS and NOS to become valid so they can be saved, so loop until they are valid.
|
||||
if muxTOS.valid = '1' and muxNOS.valid = '1' then
|
||||
-- We got an interrupt, execute interrupt instead of next instruction
|
||||
intTriggered <= '0';
|
||||
inInterrupt <= '1';
|
||||
INT_ACK <= '1'; -- Acknowledge interrupt.
|
||||
interruptSuspendedAddr <= pc(ADDR_BIT_RANGE); -- Save address which got interrupted.
|
||||
@@ -1775,6 +1763,11 @@ begin
|
||||
mxFifoWriteIdx <= mxFifoWriteIdx + 1;
|
||||
|
||||
-- All Im combinations sign extend the 7th bit of the first Im instruction then just overwrite the bits available.
|
||||
--if cacheL1(to_integer(pc))(6) = '1' then
|
||||
-- TOS.word <= "11111111111111111111111110000000";
|
||||
--else
|
||||
-- TOS.word <= (others => '0');
|
||||
--end if;
|
||||
for i in wordSize-1 downto 7 loop
|
||||
TOS.word(i) <= cacheL1(to_integer(pc))(6);
|
||||
end loop;
|
||||
@@ -1826,21 +1819,23 @@ begin
|
||||
-- Same for extended instructions.
|
||||
--
|
||||
-- 5 Consecutive IM's
|
||||
if cacheL1FetchIdx - pc > 5 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(pc)+1)(7) = '1' and cacheL1(to_integer(pc)+2)(7) = '1' and cacheL1(to_integer(pc)+3)(7) = '1' and cacheL1(to_integer(pc)+4)(7) = '1' and cacheL1(to_integer(pc)+5)(7) = '0' then
|
||||
TOS.word(31 downto 0) <= unsigned(cacheL1(to_integer(pc))(3 downto 0)) & unsigned(cacheL1(to_integer(pc)+1)(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+2)(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+3)(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+4)(OPCODE_IM_RANGE));
|
||||
pc <= pc + 5;
|
||||
--if cacheL1FetchIdx - pc > 5 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(incPC))(7) = '1' and cacheL1(to_integer(incIncPC))(7) = '1' and cacheL1(to_integer(inc3PC))(7) = '1' and cacheL1(to_integer(inc4PC))(7) = '1' and cacheL1(to_integer(inc5PC))(7) = '0' then
|
||||
if cacheL1InsnAfterPC > 5 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(incPC))(7) = '1' and cacheL1(to_integer(incIncPC))(7) = '1' and cacheL1(to_integer(inc3PC))(7) = '1' and cacheL1(to_integer(inc4PC))(7) = '1' and cacheL1(to_integer(inc5PC))(7) = '0' then
|
||||
TOS.word(31 downto 0) <= unsigned(cacheL1(to_integer(pc))(3 downto 0)) & unsigned(cacheL1(to_integer(incPC))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(incIncPC))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(inc3PC))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(inc4PC))(OPCODE_IM_RANGE));
|
||||
pc <= inc5PC;
|
||||
-- 4 Consecutive IM's
|
||||
elsif cacheL1FetchIdx - pc > 4 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(pc)+1)(7) = '1' and cacheL1(to_integer(pc)+2)(7) = '1' and cacheL1(to_integer(pc)+3)(7) = '1' and cacheL1(to_integer(pc)+4)(7) = '0' then
|
||||
TOS.word(27 downto 0) <= unsigned(cacheL1(to_integer(pc))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+1)(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+2)(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+3)(OPCODE_IM_RANGE));
|
||||
pc <= pc + 4;
|
||||
--elsif cacheL1FetchIdx - pc > 4 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(incPC))(7) = '1' and cacheL1(to_integer(incIncPC))(7) = '1' and cacheL1(to_integer(inc3PC))(7) = '1' and cacheL1(to_integer(inc4PC))(7) = '0' then
|
||||
elsif cacheL1InsnAfterPC > 4 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(incPC))(7) = '1' and cacheL1(to_integer(incIncPC))(7) = '1' and cacheL1(to_integer(inc3PC))(7) = '1' and cacheL1(to_integer(inc4PC))(7) = '0' then
|
||||
TOS.word(27 downto 0) <= unsigned(cacheL1(to_integer(pc))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(incPC))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(incIncPC))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(inc3PC))(OPCODE_IM_RANGE));
|
||||
pc <= inc4PC;
|
||||
-- 3 Consecutive IM's
|
||||
elsif cacheL1FetchIdx - pc > 3 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(pc)+1)(7) = '1' and cacheL1(to_integer(pc)+2)(7) = '1' and cacheL1(to_integer(pc)+3)(7) = '0' then
|
||||
TOS.word(20 downto 0) <= unsigned(cacheL1(to_integer(pc))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+1)(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+2)(OPCODE_IM_RANGE));
|
||||
pc <= pc + 3;
|
||||
elsif cacheL1InsnAfterPC > 3 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(incPC))(7) = '1' and cacheL1(to_integer(incIncPC))(7) = '1' and cacheL1(to_integer(inc3PC))(7) = '0' then
|
||||
TOS.word(20 downto 0) <= unsigned(cacheL1(to_integer(pc))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(incPC))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(incIncPC))(OPCODE_IM_RANGE));
|
||||
pc <= inc3PC;
|
||||
-- 2 Consecutive IM's
|
||||
elsif cacheL1FetchIdx - pc > 2 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(pc)+1)(7) = '1' and cacheL1(to_integer(pc)+2)(7) = '0' then
|
||||
TOS.word(13 downto 0) <= unsigned(cacheL1(to_integer(pc))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(pc)+1)(OPCODE_IM_RANGE));
|
||||
pc <= pc + 2;
|
||||
elsif cacheL1InsnAfterPC > 2 and cacheL1(to_integer(pc))(7) = '1' and cacheL1(to_integer(incPC))(7) = '1' and cacheL1(to_integer(incIncPC))(7) = '0' then
|
||||
TOS.word(13 downto 0) <= unsigned(cacheL1(to_integer(pc))(OPCODE_IM_RANGE)) & unsigned(cacheL1(to_integer(incPC))(OPCODE_IM_RANGE));
|
||||
pc <= incIncPC;
|
||||
-- 1 IM
|
||||
else
|
||||
TOS.word(IM_DATA_RANGE) <= unsigned(cacheL1(to_integer(pc))(OPCODE_RANGE)(IM_DATA_RANGE));
|
||||
@@ -2348,48 +2343,12 @@ begin
|
||||
when Insn_Mult =>
|
||||
if IMPL_MULT = true then
|
||||
if muxTOS.valid = '1' and muxNOS.valid = '1' then
|
||||
if DEBUG_CPU = true and DEBUG_LEVEL >= 5 then
|
||||
debugRec.FMT_DATA_PRTMODE <= "01";
|
||||
debugRec.FMT_PRE_SPACE <= '0';
|
||||
debugRec.FMT_POST_SPACE <= '1';
|
||||
debugRec.FMT_PRE_CR <= '1';
|
||||
debugRec.FMT_POST_CRLF <= '1';
|
||||
debugRec.FMT_SPLIT_DATA <= "00";
|
||||
debugRec.DATA_BYTECNT <= std_logic_vector(to_unsigned(7, 3));
|
||||
debugRec.DATA2_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
||||
debugRec.DATA3_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
||||
debugRec.DATA4_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
||||
debugRec.WRITE_DATA <= '1';
|
||||
debugRec.WRITE_DATA2 <= '0';
|
||||
debugRec.WRITE_DATA3 <= '0';
|
||||
debugRec.WRITE_DATA4 <= '0';
|
||||
debugRec.WRITE_OPCODE <= '1';
|
||||
debugRec.WRITE_DECODED_OPCODE <= '1';
|
||||
debugRec.WRITE_PC <= '1';
|
||||
debugRec.WRITE_SP <= '1';
|
||||
debugRec.WRITE_STACK_TOS <= '1';
|
||||
debugRec.WRITE_STACK_NOS <= '1';
|
||||
debugRec.DATA(63 downto 0) <= std_logic_vector(tMultResult);
|
||||
debugRec.OPCODE <= cacheL1(to_integer(pc))(OPCODE_RANGE);
|
||||
debugRec.DECODED_OPCODE <= std_logic_vector(to_unsigned(InsnType'POS(InsnType'VAL(to_integer(unsigned(cacheL1(to_integer(pc))(DECODED_RANGE))))) , 6));
|
||||
debugRec.PC(ADDR_BIT_RANGE) <= std_logic_vector(pc);
|
||||
debugRec.SP(ADDR_32BIT_RANGE) <= std_logic_vector(sp);
|
||||
debugRec.STACK_TOS <= std_logic_vector(muxTOS.word);
|
||||
debugRec.STACK_NOS <= std_logic_vector(muxNOS.word);
|
||||
debugLoad <= '1';
|
||||
end if;
|
||||
|
||||
tInsnExec := '1';
|
||||
idimFlag <= '0';
|
||||
pc <= incPC;
|
||||
sp <= incSp;
|
||||
TOS.word <= tMultResult(wordSize-1 downto 0);
|
||||
|
||||
mxFifo(to_integer(mxFifoWriteIdx)).addr(ADDR_32BIT_RANGE) <= std_logic_vector(incIncSp);
|
||||
mxFifo(to_integer(mxFifoWriteIdx)).cmd <= MX_CMD_READNOS;
|
||||
NOS.valid <= '0';
|
||||
mxFifoWriteIdx <= mxFifoWriteIdx + 1;
|
||||
--state <= State_Execute;
|
||||
state <= State_Mult2;
|
||||
multResult <= muxTOS.word * muxNOS.word;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
@@ -2777,7 +2736,8 @@ begin
|
||||
end if;
|
||||
|
||||
-- Debug code, if enabled, writes out the current instruction.
|
||||
if DEBUG_CPU = true and DEBUG_LEVEL >= 1 and tInsnExec = '1' then
|
||||
--if ((DEBUG_CPU = true and DEBUG_LEVEL >= 1) or (DEBUG_CPU = true and pc >= X"00010000")) and tInsnExec = '1' then
|
||||
if ((DEBUG_CPU = true and DEBUG_LEVEL >= 1)) and tInsnExec = '1' then
|
||||
debugRec.FMT_DATA_PRTMODE <= "01";
|
||||
debugRec.FMT_PRE_SPACE <= '0';
|
||||
debugRec.FMT_POST_SPACE <= '1';
|
||||
@@ -2818,7 +2778,7 @@ begin
|
||||
debugState <= Debug_DumpL2;
|
||||
end if;
|
||||
end if;
|
||||
if DEBUG_CPU = true and DEBUG_LEVEL >= 1 then
|
||||
if (DEBUG_CPU = true and DEBUG_LEVEL >= 1) then --or (DEBUG_CPU = true and pc >= X"00010000") then
|
||||
debugRec.FMT_DATA_PRTMODE <= "01";
|
||||
debugRec.FMT_PRE_SPACE <= '0';
|
||||
debugRec.FMT_POST_SPACE <= '1';
|
||||
@@ -2859,6 +2819,45 @@ begin
|
||||
-- End of Instruction Execution Case block.
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
when State_Mult2 =>
|
||||
if DEBUG_CPU = true and DEBUG_LEVEL >= 5 then
|
||||
debugRec.FMT_DATA_PRTMODE <= "01";
|
||||
debugRec.FMT_PRE_SPACE <= '0';
|
||||
debugRec.FMT_POST_SPACE <= '1';
|
||||
debugRec.FMT_PRE_CR <= '1';
|
||||
debugRec.FMT_POST_CRLF <= '1';
|
||||
debugRec.FMT_SPLIT_DATA <= "00";
|
||||
debugRec.DATA_BYTECNT <= std_logic_vector(to_unsigned(7, 3));
|
||||
debugRec.DATA2_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
||||
debugRec.DATA3_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
||||
debugRec.DATA4_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
||||
debugRec.WRITE_DATA <= '1';
|
||||
debugRec.WRITE_DATA2 <= '0';
|
||||
debugRec.WRITE_DATA3 <= '0';
|
||||
debugRec.WRITE_DATA4 <= '0';
|
||||
debugRec.WRITE_OPCODE <= '1';
|
||||
debugRec.WRITE_DECODED_OPCODE <= '1';
|
||||
debugRec.WRITE_PC <= '1';
|
||||
debugRec.WRITE_SP <= '1';
|
||||
debugRec.WRITE_STACK_TOS <= '1';
|
||||
debugRec.WRITE_STACK_NOS <= '1';
|
||||
debugRec.DATA(63 downto 0) <= std_logic_vector(multResult);
|
||||
debugRec.OPCODE <= cacheL1(to_integer(pc))(OPCODE_RANGE);
|
||||
debugRec.DECODED_OPCODE <= std_logic_vector(to_unsigned(InsnType'POS(InsnType'VAL(to_integer(unsigned(cacheL1(to_integer(pc))(DECODED_RANGE))))) , 6));
|
||||
debugRec.PC(ADDR_BIT_RANGE) <= std_logic_vector(pc);
|
||||
debugRec.SP(ADDR_32BIT_RANGE) <= std_logic_vector(sp);
|
||||
debugRec.STACK_TOS <= std_logic_vector(muxTOS.word);
|
||||
debugRec.STACK_NOS <= std_logic_vector(muxNOS.word);
|
||||
debugLoad <= '1';
|
||||
end if;
|
||||
|
||||
TOS.word <= multResult(wordSize-1 downto 0);
|
||||
mxFifo(to_integer(mxFifoWriteIdx)).addr(ADDR_32BIT_RANGE) <= std_logic_vector(incSp);
|
||||
mxFifo(to_integer(mxFifoWriteIdx)).cmd <= MX_CMD_READNOS;
|
||||
NOS.valid <= '0';
|
||||
mxFifoWriteIdx <= mxFifoWriteIdx + 1;
|
||||
state <= State_Execute;
|
||||
|
||||
when State_Div2 =>
|
||||
if IMPL_DIV = true then
|
||||
if DEBUG_CPU = true and DEBUG_LEVEL >= 5 then
|
||||
|
||||
@@ -48,12 +48,12 @@ package zpu_pkg is
|
||||
constant EVO_USE_INSN_BUS : boolean := true; -- Use a seperate instruction bus to connect to the BRAM memory. All other operations go over the normal bus.
|
||||
constant EVO_USE_HW_BYTE_WRITE : boolean := true; -- Implement hardware writing of bytes, reads are always 32bit and aligned.
|
||||
constant EVO_USE_HW_WORD_WRITE : boolean := true; -- Implement hardware writing of 16bit words, reads are always 32bit and aligned.
|
||||
constant EVO_USE_WB_BUS : boolean := true; -- Implement the wishbone interface in addition to the standard direct interface. NB: Change WB_ACTIVE to 1 above if enabling.
|
||||
constant EVO_USE_WB_BUS : boolean := false; -- Implement the wishbone interface in addition to the standard direct interface. NB: Change WB_ACTIVE to 1 above if enabling.
|
||||
|
||||
-- Debug options.
|
||||
--
|
||||
constant DEBUG_CPU : boolean := false; -- Enable CPU debugging output.
|
||||
constant DEBUG_LEVEL : integer := 1; -- Level of debugging output. 0 = Basic, such as Breakpoint, 1 =+ Executing Instructions, 2 =+ L1 Cache contents, 3 =+ L2 Cache contents, 4 =+ Memory contents, 5=+ 4Everything else.
|
||||
constant DEBUG_CPU : boolean := true; -- Enable CPU debugging output.
|
||||
constant DEBUG_LEVEL : integer := 0; -- Level of debugging output. 0 = Basic, such as Breakpoint, 1 =+ Executing Instructions, 2 =+ L1 Cache contents, 3 =+ L2 Cache contents, 4 =+ Memory contents, 5=+ 4Everything else.
|
||||
constant DEBUG_MAX_TX_FIFO_BITS : integer := 12; -- Size of UART TX Fifo for debug output.
|
||||
constant DEBUG_MAX_FIFO_BITS : integer := 3; -- Size of debug output data records fifo.
|
||||
constant DEBUG_TX_BAUD_RATE : integer := 115200; --230400; -- Baud rate for the debug transmitter.
|
||||
@@ -80,9 +80,12 @@ package zpu_pkg is
|
||||
subtype ADDR_16BIT_RANGE is natural range maxAddrBit-1 downto 1; -- Full address range - 2 bytes (16bit) aligned
|
||||
subtype ADDR_32BIT_RANGE is natural range maxAddrBit-1 downto minAddrBit; -- Full address range - 4 bytes (32bit) aligned
|
||||
subtype ADDR_64BIT_RANGE is natural range maxAddrBit-1 downto minAddrBit+1; -- Full address range - 8 bytes (64bit) aligned
|
||||
-- subtype ADDR_MEM_32BIT_RANGE is natural range maxAddrBit-1 downto minAddrBit; -- Non-EVO: Memory range.
|
||||
subtype ADDR_IOBIT_RANGE is natural range ioBit downto minAddrBit; -- Non-EVO: IO range.
|
||||
subtype WORD_32BIT_RANGE is natural range wordSize-1 downto 0; -- Number of bits in a word (normally 32 for this CPU).
|
||||
subtype WORD_16BIT_RANGE is natural range (wordSize/2)-1 downto 0; -- Number of bits in a half-word (normally 16 for this CPU).
|
||||
subtype WORD_UPPER_16BIT_RANGE is natural range (wordSize/2)-1 downto wordSize/4; -- Number of bits in a half-word (normally 16 for this CPU).
|
||||
subtype WORD_LOWER_16BIT_RANGE is natural range (wordSize/4)-1 downto 0; -- Number of bits in a half-word (normally 16 for this CPU).
|
||||
subtype WORD_8BIT_RANGE is natural range (wordSize/4)-1 downto 0; -- Number of bits in a byte (normally 8 for this CPU).
|
||||
subtype WORD_4BYTE_RANGE is natural range wordBytes-1 downto 0; -- Bits needed to represent wordSize in bytes (normally 4 for 32bits).
|
||||
subtype BYTE_RANGE is natural range 7 downto 0; -- Number of bits in a byte.
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ entity zpu_uart_debug is
|
||||
generic (
|
||||
TX_FIFO_BIT_DEPTH : integer := DEBUG_MAX_TX_FIFO_BITS;
|
||||
DBG_FIFO_BIT_DEPTH : integer := DEBUG_MAX_FIFO_BITS;
|
||||
CLK_FREQ : integer := 100000000;
|
||||
CLK_FREQ : integer := 100000000;
|
||||
TX_BAUD_RATE : integer := DEBUG_TX_BAUD_RATE -- Default baud rate
|
||||
);
|
||||
port (
|
||||
|
||||
2
devices/WishBone/SDRAM/48LC16M16.qip
Normal file
@@ -0,0 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) wbsdram.vhd ]
|
||||
#set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) 48LC16M16.sdc ]
|
||||
90
devices/WishBone/SDRAM/48LC16M16.sdc
Normal file
@@ -0,0 +1,90 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Constraints definition original author:
|
||||
# 8/19/2014 D. W. Hawkings (dwh@ovro.caltech.edu)
|
||||
# Adapted and enhanced for the Micron 48LC16M16 SDRAM by Philip Smart Dec 2019.
|
||||
# ------------------------------------------------------------------------------
|
||||
derive_pll_clocks
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Clock
|
||||
# Set these variables to the system and memory clock PLL paths for
|
||||
# your board.
|
||||
# -----------------------------------------------------------------
|
||||
set sysclk_pll "mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk"
|
||||
set memclk_pll "mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|divclk"
|
||||
create_generated_clock -name SDRAM_CLK -source $memclk_pll [get_ports {SDRAM_CLK}]
|
||||
derive_clock_uncertainty
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Constraints
|
||||
# -----------------------------------------------------------------
|
||||
#
|
||||
# SDRAM timing parameters
|
||||
#
|
||||
# Generally, the command/address/data all have the same setup/hold
|
||||
# time.
|
||||
#
|
||||
# SDRAM clock can lead System clock by min:
|
||||
# tlead = tcoutmin(FPGA) – th(SDRAM)
|
||||
#
|
||||
# SDRAM clock can lag System clock by min:
|
||||
# tlag = toh(SDRAM) – th(FPGA)
|
||||
#
|
||||
# tSU = Data Setup time (ie. tDS, tAS) on falling edge.
|
||||
# tH = Hold time (ie. tDH, tAH) for SDRAM.
|
||||
# tCOUT (min) = Data out hold time (ie. tOH)
|
||||
# tCOUT (max) = Access time for CL in use (ie. tAC3).
|
||||
#
|
||||
set sdram_tsu 1.5
|
||||
set sdram_th 0.8
|
||||
set sdram_tco_min 3.0
|
||||
set sdram_tco_max 5.4
|
||||
|
||||
# FPGA timing constraints
|
||||
set sdram_input_delay_min $sdram_tco_min
|
||||
set sdram_input_delay_max $sdram_tco_max
|
||||
set sdram_output_delay_min -$sdram_th
|
||||
set sdram_output_delay_max $sdram_tsu
|
||||
|
||||
# PLL to FPGA output (clear the unconstrained path warning)
|
||||
#set_min_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 1
|
||||
#set_max_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 6
|
||||
|
||||
# FPGA Outputs
|
||||
set sdram_outputs [get_ports {
|
||||
SDRAM_CKE
|
||||
SDRAM_CS
|
||||
SDRAM_RAS
|
||||
SDRAM_CAS
|
||||
SDRAM_WE
|
||||
SDRAM_DQM[*]
|
||||
SDRAM_BA[*]
|
||||
SDRAM_ADDR[*]
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_output_delay -clock SDRAM_CLK -min $sdram_output_delay_min $sdram_outputs
|
||||
set_output_delay -clock SDRAM_CLK -max $sdram_output_delay_max $sdram_outputs
|
||||
|
||||
# FPGA Inputs
|
||||
set sdram_inputs [get_ports {
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_input_delay -clock SDRAM_CLK -min $sdram_input_delay_min $sdram_inputs
|
||||
set_input_delay -clock SDRAM_CLK -max $sdram_input_delay_max $sdram_inputs
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM-to-FPGA multi-cycle constraint
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# The PLL is configured so that SDRAM clock leads the system
|
||||
# clock by ~90-degrees (0.25 period or 2.5ns for 100MHz clock).
|
||||
# This will need changing for different clocks, in the PLL
|
||||
# RTL file and the SoC contraints file.
|
||||
|
||||
# The following multi-cycle constraint declares to TimeQuest that
|
||||
# the path between the SDRAM_CLK and the System Clock can be an
|
||||
# extra clock period to the read path to ensure that the latch
|
||||
# clock that occurs 1.25 periods after the launch clock is used in
|
||||
# the timing analysis.
|
||||
#
|
||||
set_multicycle_path -setup -end -from SDRAM_CLK -to $sysclk_pll 2
|
||||
2
devices/WishBone/SDRAM/48LC16M16_cached.qip
Normal file
@@ -0,0 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) wbsdram_cached.vhd ]
|
||||
#set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) 48LC16M16.sdc ]
|
||||
2
devices/WishBone/SDRAM/W9864G6.qip
Normal file
@@ -0,0 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) wbsdram.vhd ]
|
||||
#set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) W9864G6.sdc ]
|
||||
90
devices/WishBone/SDRAM/W9864G6.sdc
Normal file
@@ -0,0 +1,90 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Constraints definition original author:
|
||||
# 8/19/2014 D. W. Hawkings (dwh@ovro.caltech.edu)
|
||||
# Adapted and enhanced for the Winbond W9864G6 SDRAM by Philip Smart Dec 2019.
|
||||
# ------------------------------------------------------------------------------
|
||||
derive_pll_clocks
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Clock
|
||||
# Set these variables to the system and memory clock PLL paths for
|
||||
# your board.
|
||||
# -----------------------------------------------------------------
|
||||
set sysclk_pll "mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk"
|
||||
set memclk_pll "mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|divclk"
|
||||
create_generated_clock -name SDRAM_CLK -source $memclk_pll [get_ports {SDRAM_CLK}]
|
||||
derive_clock_uncertainty
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Constraints
|
||||
# -----------------------------------------------------------------
|
||||
#
|
||||
# SDRAM timing parameters
|
||||
#
|
||||
# Generally, the command/address/data all have the same setup/hold
|
||||
# time.
|
||||
#
|
||||
# SDRAM clock can lead System clock by min:
|
||||
# tlead = tcoutmin(FPGA) – th(SDRAM)
|
||||
#
|
||||
# SDRAM clock can lag System clock by min:
|
||||
# tlag = toh(SDRAM) – th(FPGA)
|
||||
#
|
||||
# tSU = Data Setup time (ie. tDS, tAS) on falling edge.
|
||||
# tH = Hold time (ie. tDH, tAH) for SDRAM.
|
||||
# tCOUT (min) = Data out hold time (ie. tOH)
|
||||
# tCOUT (max) = Access time for CL in use (ie. tAC3).
|
||||
#
|
||||
set sdram_tsu 1.5
|
||||
set sdram_th 0.8
|
||||
set sdram_tco_min 3.0
|
||||
set sdram_tco_max 5.0
|
||||
|
||||
# FPGA timing constraints
|
||||
set sdram_input_delay_min $sdram_tco_min
|
||||
set sdram_input_delay_max $sdram_tco_max
|
||||
set sdram_output_delay_min -$sdram_th
|
||||
set sdram_output_delay_max $sdram_tsu
|
||||
|
||||
# PLL to FPGA output (clear the unconstrained path warning)
|
||||
#set_min_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 1
|
||||
#set_max_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 6
|
||||
|
||||
# FPGA Outputs
|
||||
set sdram_outputs [get_ports {
|
||||
SDRAM_CKE
|
||||
SDRAM_CS
|
||||
SDRAM_RAS
|
||||
SDRAM_CAS
|
||||
SDRAM_WE
|
||||
SDRAM_DQM[*]
|
||||
SDRAM_BA[*]
|
||||
SDRAM_ADDR[*]
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_output_delay -clock SDRAM_CLK -min $sdram_output_delay_min $sdram_outputs
|
||||
set_output_delay -clock SDRAM_CLK -max $sdram_output_delay_max $sdram_outputs
|
||||
|
||||
# FPGA Inputs
|
||||
set sdram_inputs [get_ports {
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_input_delay -clock SDRAM_CLK -min $sdram_input_delay_min $sdram_inputs
|
||||
set_input_delay -clock SDRAM_CLK -max $sdram_input_delay_max $sdram_inputs
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM-to-FPGA multi-cycle constraint
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# The PLL is configured so that SDRAM clock leads the system
|
||||
# clock by ~90-degrees (0.25 period or 2.5ns for 100MHz clock).
|
||||
# This will need changing for different clocks, in the PLL
|
||||
# RTL file and the SoC contraints file.
|
||||
|
||||
# The following multi-cycle constraint declares to TimeQuest that
|
||||
# the path between the SDRAM_CLK and the System Clock can be an
|
||||
# extra clock period to the read path to ensure that the latch
|
||||
# clock that occurs 1.25 periods after the launch clock is used in
|
||||
# the timing analysis.
|
||||
#
|
||||
set_multicycle_path -setup -end -from SDRAM_CLK -to $sysclk_pll 2
|
||||
2
devices/WishBone/SDRAM/W9864G6_cached.qip
Normal file
@@ -0,0 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) wbsdram_cached.vhd ]
|
||||
#set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) W9864G6.sdc ]
|
||||
@@ -1,26 +0,0 @@
|
||||
derive_pll_clocks
|
||||
|
||||
#create_generated_clock -source [get_pins -compatibility_mode {*|pll|pll_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk}]
|
||||
#{*mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk}] \
|
||||
|
||||
#create_generated_clock -source [get_pins -compatibility_mode {mypll|altpll_component|pll|clk[1]}] \
|
||||
# -name MEMCLK [get_ports {MEMCLK}]
|
||||
#create_generated_clock -source [get_pins -compatibility_mode {mypll|altpll_component|pll|clk[1]}] -multiply_by 1 \
|
||||
# -name MEMCLK [get_ports {MEMCLK}]
|
||||
#create_generated_clock -name {MEMCLK} -source [get_ports {CLOCK_12M}] -duty_cycle 50.000 -multiply_by 25 -divide_by 2 -master_clock {clk_12} [get_nets {mypll|altpll_component|_clk1}]
|
||||
#create_generated_clock -name {MEMCLK} -source [get_pins -compatibility_mode {mypll|altpll_component|pll|clk[1]}] -master_clock {MEMCLK} [get_ports {MEMCLK}]
|
||||
|
||||
derive_clock_uncertainty
|
||||
|
||||
# Set acceptable delays for SDRAM chip (See correspondent chip datasheet)
|
||||
set_input_delay -max -clock MEMCLK 6.4ns [get_ports SDRAM_DQ[*]]
|
||||
set_input_delay -min -clock MEMCLK 3.7ns [get_ports SDRAM_DQ[*]]
|
||||
|
||||
# -to [get_clocks {*|pll|pll_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk}]
|
||||
#set_multicycle_path -from [get_clocks {MEMCLK}] \
|
||||
# -to [get_clocks {SYSCLK}] \
|
||||
# -setup 2
|
||||
|
||||
|
||||
set_output_delay -max -clock MEMCLK 1.6ns [get_ports {SDRAM_D* SDRAM_ADDR* SDRAM_BA* SDRAM_CS SDRAM_WE SDRAM_RAS SDRAM_CAS SDRAM_CKE}]
|
||||
set_output_delay -min -clock MEMCLK -0.9ns [get_ports {SDRAM_D* SDRAM_ADDR* SDRAM_BA* SDRAM_CS SDRAM_WE SDRAM_RAS SDRAM_CAS SDRAM_CKE}]
|
||||
@@ -2,22 +2,21 @@
|
||||
--
|
||||
-- Name: wbsdram.vhd
|
||||
-- Created: September 2019
|
||||
-- Original Author: Stephen J. Leary 2013-2014
|
||||
-- VHDL Author: Philip Smart
|
||||
-- Description: Original Wishbone module written by Stephen J. Leary 2013-2014 in Verilog for use
|
||||
-- with the MT48LC16M16 chip.
|
||||
-- It has been translated into VHDL and adapted for the system bus and undergoing
|
||||
-- extensive modifications to work with the ZPU EVO processor, specifically burst
|
||||
-- tuning to enhance L2 Cache Fill performance.
|
||||
-- Credits:
|
||||
-- Copyright: Copyright (c) 2013-2014, Stephen J. Leary, All rights reserved.
|
||||
-- VHDL translation, sysbus adaptation and enhancements (c) 2019 Philip Smart
|
||||
-- <philip.smart@net2net.org>
|
||||
-- Author: Philip Smart
|
||||
-- Description: A configurable cached sdram controller for use with the ZPU EVO Processor and SoC.
|
||||
-- The module is instantiated with the parameters to describe the underlying SDRAM chip
|
||||
-- and in theory should work with most 16/32 bit SDRAM chips if they adhere to the SDRAM
|
||||
-- standard.
|
||||
-- Credits: Stephen J. Leary 2013-2014 - Basic sdram cycle structure of this module was based on
|
||||
-- the verilog MT48LC16M16 chip controller written by Stephen.
|
||||
-- Copyright: (c) 2019-2020 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: September 2019 - Initial module translation to VHDL based on Stephen J. Leary's Verilog
|
||||
-- source code.
|
||||
-- November 2019 - Adapted for the system bus for use when no Wishbone interface is
|
||||
-- instantiated in the ZPU Evo.
|
||||
-- December 2019 - Extensive changes, metability stability, autorefresh to ACTIVE timing
|
||||
-- and parameterisation.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- This source file is free software: you can redistribute it and-or modify
|
||||
@@ -43,85 +42,98 @@ use work.zpu_pkg.all;
|
||||
|
||||
entity WBSDRAM is
|
||||
generic (
|
||||
MAX_DATACACHE_BITS : integer := 4; -- Maximum size in addr bits of 32bit datacache for burst transactions.
|
||||
SDRAM_COLUMNS : integer := 256; -- Number of Columns in an SDRAM page (ie. 1 row).
|
||||
SDRAM_ROWS : integer := 4096; -- Number of Rows in the SDRAM.
|
||||
SDRAM_BANKS : integer := 4 -- Number of banks in the SDRAM.
|
||||
MAX_DATACACHE_BITS : integer := 4; -- Maximum size in addr bits of 32bit datacache for burst transactions.
|
||||
SDRAM_ROWS : integer := 4096; -- Number of Rows in the SDRAM.
|
||||
SDRAM_COLUMNS : integer := 256; -- Number of Columns in an SDRAM page (ie. 1 row).
|
||||
SDRAM_BANKS : integer := 4; -- Number of banks in the SDRAM.
|
||||
SDRAM_DATAWIDTH : integer := 16; -- Data width of SDRAM chip (16, 32).
|
||||
SDRAM_CLK_FREQ : integer := 100000000; -- Frequency of the SDRAM clock in Hertz.
|
||||
SDRAM_tRCD : integer := 20; -- tRCD - RAS to CAS minimum period (in ns).
|
||||
SDRAM_tRP : integer := 20; -- tRP - Precharge delay, min time for a precharge command to complete (in ns).
|
||||
SDRAM_tRFC : integer := 70; -- tRFC - Auto-refresh minimum time to complete (in ns), ie. 66ns
|
||||
SDRAM_tREF : integer := 64 -- tREF - period of time a complete refresh of all rows is made within (in ms).
|
||||
);
|
||||
port (
|
||||
-- SDRAM Interface
|
||||
SDRAM_CLK : in std_logic; -- sdram is accessed at 100MHz
|
||||
SDRAM_RST : in std_logic; -- reset the sdram controller.
|
||||
SDRAM_CKE : out std_logic; -- clock enable.
|
||||
SDRAM_DQ : inout std_logic_vector(15 downto 0); -- 16 bit bidirectional data bus
|
||||
SDRAM_ADDR : out std_logic_vector(log2ceil(SDRAM_ROWS) - 1 downto 0); -- Multiplexed address bus
|
||||
SDRAM_DQM : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of byte masks dependent on number of banks.
|
||||
SDRAM_BA : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of banks in SDRAM
|
||||
SDRAM_CS_n : out std_logic; -- Single chip select
|
||||
SDRAM_WE_n : out std_logic; -- write enable
|
||||
SDRAM_RAS_n : out std_logic; -- row address select
|
||||
SDRAM_CAS_n : out std_logic; -- columns address select
|
||||
SDRAM_READY : out std_logic; -- sd ready.
|
||||
|
||||
SDRAM_CLK : in std_logic; -- SDRAM is accessed at given clock, frequency specified in RAM_CLK.
|
||||
SDRAM_RST : in std_logic; -- Reset the sdram controller.
|
||||
SDRAM_CKE : out std_logic; -- Clock enable.
|
||||
SDRAM_DQ : inout std_logic_vector(SDRAM_DATAWIDTH-1 downto 0); -- Bidirectional data bus
|
||||
SDRAM_ADDR : out std_logic_vector(log2ceil(SDRAM_ROWS) - 1 downto 0); -- Multiplexed address bus
|
||||
SDRAM_DQM : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of byte masks dependent on number of banks.
|
||||
SDRAM_BA : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of banks in SDRAM
|
||||
SDRAM_CS_n : out std_logic; -- Single chip select
|
||||
SDRAM_WE_n : out std_logic; -- Write enable
|
||||
SDRAM_RAS_n : out std_logic; -- Row address select
|
||||
SDRAM_CAS_n : out std_logic; -- Columns address select
|
||||
SDRAM_READY : out std_logic; -- SD ready.
|
||||
|
||||
-- WishBone interface.
|
||||
WB_CLK : in std_logic; -- Master clock at which the Wishbone interface operates.
|
||||
WB_RST_I : in std_logic; -- high active sync reset
|
||||
WB_DATA_I : in std_logic_vector(WORD_32BIT_RANGE); -- Data input from Master
|
||||
WB_DATA_O : out std_logic_vector(WORD_32BIT_RANGE); -- Data output to Master
|
||||
WB_ACK_O : out std_logic;
|
||||
WB_ADR_I : in std_logic_vector(21 downto 0); -- lower 2 bits are ignored.
|
||||
WB_SEL_I : in std_logic_vector(3 downto 0);
|
||||
WB_CTI_I : in std_logic_vector(2 downto 0); -- 000 Classic cycle, 001 Constant address burst cycle, 010 Incrementing burst cycle, 111 End-of-Burst
|
||||
WB_STB_I : in std_logic;
|
||||
WB_CYC_I : in std_logic; -- cpu/chipset requests cycle
|
||||
WB_WE_I : in std_logic; -- cpu/chipset requests write
|
||||
WB_TGC_I : in std_logic_vector(06 downto 0); -- cycle tag
|
||||
WB_HALT_O : out std_logic; -- throttle master
|
||||
WB_ERR_O : out std_logic -- abnormal cycle termination
|
||||
WB_CLK : in std_logic; -- Master clock at which the Wishbone interface operates.
|
||||
WB_RST_I : in std_logic; -- high active sync reset
|
||||
WB_DATA_I : in std_logic_vector(WORD_32BIT_RANGE); -- Data input from Master
|
||||
WB_DATA_O : out std_logic_vector(WORD_32BIT_RANGE); -- Data output to Master
|
||||
WB_ACK_O : out std_logic;
|
||||
WB_ADR_I : in std_logic_vector(log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS) downto 0);
|
||||
WB_SEL_I : in std_logic_vector(3 downto 0);
|
||||
WB_CTI_I : in std_logic_vector(2 downto 0); -- 000 Classic cycle, 001 Constant address burst cycle, 010 Incrementing burst cycle, 111 End-of-Burst
|
||||
WB_STB_I : in std_logic;
|
||||
WB_CYC_I : in std_logic; -- cpu/chipset requests cycle
|
||||
WB_WE_I : in std_logic; -- cpu/chipset requests write
|
||||
WB_TGC_I : in std_logic_vector(06 downto 0); -- cycle tag
|
||||
WB_HALT_O : out std_logic; -- throttle master
|
||||
WB_ERR_O : out std_logic -- abnormal cycle termination
|
||||
);
|
||||
end WBSDRAM;
|
||||
|
||||
architecture Structure of WBSDRAM is
|
||||
|
||||
-- Constants to define the structure of the SDRAM in bits for provisioning of signals.
|
||||
constant SDRAM_ROW_BITS : integer := log2ceil(SDRAM_ROWS);
|
||||
constant SDRAM_COLUMN_BITS: integer := log2ceil(SDRAM_COLUMNS);
|
||||
constant SDRAM_ARRAY_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS);
|
||||
constant SDRAM_BANK_BITS : integer := log2ceil(SDRAM_BANKS);
|
||||
constant SDRAM_ADDR_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS);
|
||||
|
||||
-- Constants for correct operation of the SDRAM, these values are taken from the datasheet of the target device.
|
||||
--
|
||||
constant tRCD : integer := 4; -- tRCD - RAS to CAS minimum period, ie. 20ns -> 2 cycles@100MHz
|
||||
constant tRP : integer := 4; -- tRP - Precharge delay, min time for a precharge command to complete, ie. 15ns -> 2 cycles@100MHz
|
||||
constant tRFC : integer := 70; -- tRFC - Auto-refresh minimum time to complete, ie. 66ns
|
||||
constant tREF : integer := 64; -- tREF - period of time a complete refresh of all rows is made within.
|
||||
constant RAM_CLK : integer := 50000000; -- SDRAM Clock in Hertz
|
||||
constant SDRAM_ROW_BITS : integer := log2ceil(SDRAM_ROWS);
|
||||
constant SDRAM_COLUMN_BITS : integer := log2ceil(SDRAM_COLUMNS);
|
||||
constant SDRAM_ARRAY_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS);
|
||||
constant SDRAM_BANK_BITS : integer := log2ceil(SDRAM_BANKS);
|
||||
constant SDRAM_ADDR_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS * (SDRAM_DATAWIDTH/8));
|
||||
|
||||
-- Command table for a standard SDRAM.
|
||||
--
|
||||
-- Name (Function) CS# RAS# CAS# WE# DQM ADDR DQ
|
||||
-- COMMAND INHIBIT (NOP) H X X X X X X
|
||||
-- NO OPERATION (NOP) L H H H X X X
|
||||
-- ACTIVE (select bank and activate row) L L H H X Bank/row X
|
||||
-- READ (select bank and column, and start READ burst) L H L H L/H Bank/col X
|
||||
-- WRITE (select bank and column, and start WRITE burst) L H L L L/H Bank/col Valid
|
||||
-- BURST TERMINATE L H H L X X Active
|
||||
-- PRECHARGE (Deactivate row in bank or banks) L L H L X Code X
|
||||
-- AUTO REFRESH or SELF REFRESH (enter self refresh mode) L L L H X X X
|
||||
-- LOAD MODE REGISTER L L L L X Op-code X
|
||||
-- Write enable/output enable X X X X L X Active
|
||||
-- Write inhibit/output High-Z X X X X H X High-Z
|
||||
constant CMD_INHIBIT : std_logic_vector(3 downto 0) := "1111";
|
||||
constant CMD_NOP : std_logic_vector(3 downto 0) := "0111";
|
||||
constant CMD_ACTIVE : std_logic_vector(3 downto 0) := "0011";
|
||||
constant CMD_READ : std_logic_vector(3 downto 0) := "0101";
|
||||
constant CMD_WRITE : std_logic_vector(3 downto 0) := "0100";
|
||||
constant CMD_BURST_TERMINATE : std_logic_vector(3 downto 0) := "0110";
|
||||
constant CMD_PRECHARGE : std_logic_vector(3 downto 0) := "0010";
|
||||
constant CMD_AUTO_REFRESH : std_logic_vector(3 downto 0) := "0001";
|
||||
constant CMD_LOAD_MODE : std_logic_vector(3 downto 0) := "0000";
|
||||
-- Name (Function) CKE CS# RAS# CAS# WE# DQM ADDR DQ
|
||||
-- COMMAND INHIBIT (NOP) H H X X X X X X
|
||||
-- NO OPERATION (NOP) H L H H H X X X
|
||||
-- ACTIVE (select bank and activate row) H L L H H X Bank/row X
|
||||
-- READ (select bank and column, and start READ burst) H L H L H L/H Bank/col X
|
||||
-- WRITE (select bank and column, and start WRITE burst) H L H L L L/H Bank/col Valid
|
||||
-- BURST TERMINATE H L H H L X X Active
|
||||
-- PRECHARGE (Deactivate row in bank or banks) H L L H L X Code X
|
||||
-- AUTO REFRESH or SELF REFRESH (enter self refresh mode) H L L L H X X X
|
||||
-- LOAD MODE REGISTER H L L L L X Op-code X
|
||||
-- Write enable/output enable H X X X X L X Active
|
||||
-- Write inhibit/output High-Z H X X X X H X High-Z
|
||||
-- Self Refresh Entry L L L L H X X X
|
||||
-- Self Refresh Exit (Device is idle) H H X X X X X X
|
||||
-- Self Refresh Exit (Device is in Self Refresh state) H L H H X X X X
|
||||
-- Clock suspend mode Entry L X X X X X X X
|
||||
-- Clock suspend mode Exit H X X X X X X X
|
||||
-- Power down mode Entry (Device is idle) L H X X X X X X
|
||||
-- Power down mode Entry (Device is Active) L L H H X X X X
|
||||
-- Power down mode Exit (Any state) H H X X X X X X
|
||||
-- Power down mode Exit (Device is powered down) H L H H X X X X
|
||||
|
||||
constant CMD_INHIBIT : std_logic_vector(4 downto 0) := "11111";
|
||||
constant CMD_NOP : std_logic_vector(4 downto 0) := "10111";
|
||||
constant CMD_ACTIVE : std_logic_vector(4 downto 0) := "10011";
|
||||
constant CMD_READ : std_logic_vector(4 downto 0) := "10101";
|
||||
constant CMD_WRITE : std_logic_vector(4 downto 0) := "10100";
|
||||
constant CMD_BURST_TERMINATE : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_PRECHARGE : std_logic_vector(4 downto 0) := "10010";
|
||||
constant CMD_AUTO_REFRESH : std_logic_vector(4 downto 0) := "10001";
|
||||
constant CMD_LOAD_MODE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_SELF_REFRESH_START : std_logic_vector(4 downto 0) := "00001";
|
||||
constant CMD_SELF_REFRESH_END : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_CLOCK_SUSPEND : std_logic_vector(4 downto 0) := "00000";
|
||||
constant CMD_CLOCK_RESTORE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_POWER_DOWN : std_logic_vector(4 downto 0) := "01000";
|
||||
constant CMD_POWER_RESTORE : std_logic_vector(4 downto 0) := "01100";
|
||||
|
||||
-- Load Mode Register setting for a standard SDRAM.
|
||||
--
|
||||
@@ -133,112 +145,93 @@ architecture Structure of WBSDRAM is
|
||||
-- 2:0 = Burst Length : When 000 = 1, 001 = 2, 010 = 4, 011 = 8, all others reserved except 111 when BT = 0 sets full page access.
|
||||
-- | A12-A10 | A9 A8-A7 | A6 A5 A4 | A3Â A2 A1 A0 |
|
||||
-- | reserved| wr burst |reserved| CAS Ltncy|addr mode| burst len|
|
||||
constant WRITE_BURST_MODE : std_logic := '1';
|
||||
constant OP_MODE : std_logic_vector(1 downto 0) := "00";
|
||||
constant CAS_LATENCY : std_logic_vector(2 downto 0) := "011";
|
||||
constant BURST_TYPE : std_logic := '0';
|
||||
constant BURST_LENGTH : std_logic_vector(2 downto 0) := "000";
|
||||
constant MODE : std_logic_vector(SDRAM_ROW_BITS-1 downto 0) := std_logic_vector(to_unsigned(to_integer(unsigned("00" & WRITE_BURST_MODE & OP_MODE & CAS_LATENCY & BURST_TYPE & BURST_LENGTH)), SDRAM_ROW_BITS));
|
||||
constant WRITE_BURST_MODE : std_logic := '1';
|
||||
constant OP_MODE : std_logic_vector(1 downto 0) := "00";
|
||||
constant CAS_LATENCY : std_logic_vector(2 downto 0) := "011";
|
||||
constant BURST_TYPE : std_logic := '0';
|
||||
constant BURST_LENGTH : std_logic_vector(2 downto 0) := "000";
|
||||
constant MODE : std_logic_vector(SDRAM_ROW_BITS-1 downto 0) := std_logic_vector(to_unsigned(to_integer(unsigned("00" & WRITE_BURST_MODE & OP_MODE & CAS_LATENCY & BURST_TYPE & BURST_LENGTH)), SDRAM_ROW_BITS));
|
||||
|
||||
-- FSM Cycle States governed in units of time, the state changes location according to the configurable parameters to ensure correct actuation at the correct time.
|
||||
--
|
||||
constant CYCLE_PRECHARGE : integer := 0; -- 0
|
||||
constant CYCLE_RAS_START : integer := tRP; -- 3
|
||||
constant CYCLE_RAS_NEXT : integer := CYCLE_RAS_START + 1; -- 4
|
||||
constant CYCLE_CAS0 : integer := CYCLE_RAS_START + tRCD; -- 3 + tRCD
|
||||
constant CYCLE_CAS1 : integer := CYCLE_CAS0 + 1; -- 4 + tRCD
|
||||
constant CYCLE_READ0 : integer := CYCLE_CAS0 + to_integer(unsigned(CAS_LATENCY)) + 1; -- 3 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_READ1 : integer := CYCLE_READ0 + 1; -- 4 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_END : integer := CYCLE_READ1 + 4; -- 9 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_RFSH_START : integer := CYCLE_RAS_START; -- 3
|
||||
constant CYCLE_RFSH_END : integer := CYCLE_RFSH_START + ((tRFC/RAM_CLK) * 10000000) + 1; -- 3 + tRFC in clock ticks.
|
||||
constant CYCLE_PRECHARGE : integer := 0; -- ~0
|
||||
constant CYCLE_RAS_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~3
|
||||
constant CYCLE_CAS_START : integer := CYCLE_RAS_START + clockTicks(SDRAM_tRCD, SDRAM_CLK_FREQ); -- ~3 + tRCD
|
||||
constant CYCLE_CAS_END : integer := CYCLE_CAS_START + 1; -- ~4 + tRCD
|
||||
constant CYCLE_READ_START : integer := CYCLE_CAS_START + to_integer(unsigned(CAS_LATENCY)) + 1; -- ~3 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_READ_END : integer := CYCLE_READ_START + 1; -- ~4 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_END : integer := CYCLE_READ_END + 1; -- ~9 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_RFSH_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~tRP
|
||||
constant CYCLE_RFSH_END : integer := CYCLE_RFSH_START + clockTicks(SDRAM_tRFC, SDRAM_CLK_FREQ) + clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ) + 1; -- ~tRP (start) + tRFC (min autorefresh time) + tRP (end) in clock ticks.
|
||||
|
||||
-- Period in clock cycles between SDRAM refresh cycles.
|
||||
constant REFRESH_PERIOD : integer := (RAM_CLK / (tREF * SDRAM_ROWS)) - CYCLE_END;
|
||||
-- Period in clock cycles between SDRAM refresh cycles. This equates to tREF / SDRAM_ROWS to evenly divide the time, then subtract the length of the refresh period as this is
|
||||
-- the time it takes when a refresh starts until completion.
|
||||
constant REFRESH_PERIOD : integer := (((SDRAM_tREF * SDRAM_CLK_FREQ ) / SDRAM_ROWS) - (SDRAM_tRFC * 1000)) / 1000;
|
||||
|
||||
type BankArray is array(natural range 0 to 3) of std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
-- Array of row addresses, one per bank, to indicate the row in use per bank.
|
||||
type BankArray is array(natural range 0 to SDRAM_BANKS-1) of std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
|
||||
-- Cache for holding burst reads to allow for differing speeds of WishBone Master.
|
||||
type DataCacheArray is array(natural range 0 to ((2**(MAX_DATACACHE_BITS))-1)) of std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal readCache : DataCacheArray;
|
||||
attribute ramstyle : string;
|
||||
attribute ramstyle of readCache : signal is "logic";
|
||||
signal cacheReadAddr : unsigned(MAX_DATACACHE_BITS-1 downto 0);
|
||||
signal cacheWriteAddr : unsigned(MAX_DATACACHE_BITS-1 downto 0);
|
||||
-- SDRAM domain signals.
|
||||
signal sdBusy : std_logic;
|
||||
signal sdCycle : integer range 0 to 31;
|
||||
signal sdDataOut : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal sdDone : std_logic;
|
||||
shared variable sdCmd : std_logic_vector(4 downto 0);
|
||||
signal sdRefreshCount : unsigned(11 downto 0);
|
||||
signal sdAutoRefresh : std_logic;
|
||||
signal sdResetTimer : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdInResetCounter : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdIsReady : std_logic;
|
||||
signal sdActiveRow : BankArray;
|
||||
signal sdActiveBank : std_logic_vector(1 downto 0);
|
||||
|
||||
signal sbBusy : std_logic;
|
||||
signal sdCycle : integer range 0 to 31;
|
||||
signal sdDone : std_logic;
|
||||
signal sdCmd : std_logic_vector(3 downto 0);
|
||||
signal sdRefreshCount : unsigned(9 downto 0);
|
||||
signal sdAutoRefresh : std_logic;
|
||||
-- CPU domain signals.
|
||||
signal cpuBusy : std_logic;
|
||||
signal cpuDQM : std_logic_vector(3 downto 0);
|
||||
signal cpuDoneLast : std_logic;
|
||||
signal cpuBank : natural range 0 to SDRAM_BANKS-1;
|
||||
signal cpuRow : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
signal cpuCol : std_logic_vector(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
signal cpuDataIn : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal cpuIsWriting : std_logic;
|
||||
signal cpuDoneAck : std_logic;
|
||||
signal wbACK : std_logic;
|
||||
|
||||
signal sdResetTimer : unsigned(7 downto 0);
|
||||
signal sdMuxAddr : std_logic_vector(SDRAM_ROW_BITS-1 downto 0); -- 12 bit multiplexed address bus
|
||||
signal sdDoneLast : std_logic;
|
||||
signal sdInResetCounter : unsigned(7 downto 0);
|
||||
signal sdIsWriting : std_logic;
|
||||
signal isReady : std_logic;
|
||||
signal sdDataOut : std_logic_vector(15 downto 0);
|
||||
signal sdDataIn : std_logic_vector(15 downto 0);
|
||||
signal sdActiveRow : BankArray;
|
||||
signal sdActiveBank : std_logic_vector(1 downto 0);
|
||||
signal sdBank : natural range 0 to 3;
|
||||
signal sdRow : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
signal sdCol : std_logic_vector(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
signal sdDQM : std_logic_vector(1 downto 0);
|
||||
signal sdCKE : std_logic;
|
||||
|
||||
signal wbACK : std_logic;
|
||||
|
||||
signal cpuDQM : std_logic_vector(3 downto 0);
|
||||
|
||||
signal dout : std_logic_vector(31 downto 0);
|
||||
signal cpuDataIn : std_logic_vector(31 downto 0);
|
||||
begin
|
||||
|
||||
-- Tri-state control of the SDRAM data bus.
|
||||
process(sdIsWriting, SDRAM_DQ, sdDataOut)
|
||||
begin
|
||||
if (sdIsWriting = '1') then
|
||||
SDRAM_DQ <= sdDataOut;
|
||||
sdDataIn <= SDRAM_DQ;
|
||||
else
|
||||
SDRAM_DQ <= (others => 'Z');
|
||||
sdDataIn <= SDRAM_DQ;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Main FSM for SDRAM control and refresh.
|
||||
process(SDRAM_CLK, SDRAM_RST)
|
||||
process(ALL)
|
||||
begin
|
||||
|
||||
if (SDRAM_RST = '1') then
|
||||
sdResetTimer <= (others => '0'); -- 0 upto 127
|
||||
sdResetTimer <= (others => '0'); -- 0 upto 255
|
||||
sdInResetCounter <= (others => '1'); -- 255 downto 0
|
||||
sdMuxAddr <= (others => '0');
|
||||
sdAutoRefresh <= '0';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
isReady <= '0';
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCKE <= '1';
|
||||
sdDQM <= (others => '1');
|
||||
sdIsReady <= '0';
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
SDRAM_DQM <= (others => '1');
|
||||
sdCycle <= 0;
|
||||
sdDone <= '0';
|
||||
cacheWriteAddr <= (others => '0');
|
||||
|
||||
elsif rising_edge(SDRAM_CLK) then
|
||||
|
||||
-- Tri-state control of the SDRAM databus, when reading, the output drivers are disabled.
|
||||
if (cpuIsWriting = '0') then
|
||||
SDRAM_DQ <= (others => 'Z');
|
||||
end if;
|
||||
|
||||
-- If no specific command given the default is NOP.
|
||||
sdCmd <= CMD_NOP;
|
||||
sdCmd := CMD_NOP;
|
||||
|
||||
-- Initialisation on power up or reset. The SDRAM must be given at least 200uS to initialise and a fixed setup pattern applied.
|
||||
if (isReady = '0') then
|
||||
if (sdIsReady = '0') then
|
||||
sdResetTimer <= sdResetTimer + 1;
|
||||
|
||||
-- 1uS timer.
|
||||
if (sdResetTimer = RAM_CLK/1000000) then
|
||||
if (sdResetTimer = SDRAM_CLK_FREQ/1000000) then
|
||||
sdResetTimer <= (others => '0');
|
||||
sdInResetCounter <= sdInResetCounter - 1;
|
||||
end if;
|
||||
@@ -251,44 +244,55 @@ begin
|
||||
|
||||
-- Precharge all banks
|
||||
if(sdInResetCounter = 55) then
|
||||
sdCmd <= CMD_PRECHARGE;
|
||||
sdMuxAddr(10) <= '1';
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 40 and sdInResetCounter <= 48) then
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- Load the Mode register with our parameters.
|
||||
if(sdInResetCounter = 39) then
|
||||
sdCmd <= CMD_LOAD_MODE;
|
||||
sdMuxAddr <= MODE;
|
||||
sdCmd := CMD_LOAD_MODE;
|
||||
SDRAM_ADDR <= MODE;
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 30 and sdInResetCounter <= 38) then
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- SDRAM ready.
|
||||
if(sdInResetCounter = 20) then
|
||||
isReady <= '1';
|
||||
sdIsReady <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
else
|
||||
|
||||
-- Counter to time periods between autorefresh.
|
||||
sdRefreshCount <= sdRefreshCount + 1;
|
||||
|
||||
-- Auto refresh. On timeout it kicks in so that 8192 auto refreshes are
|
||||
-- issued in a 64ms period. Other bus operations are stalled during this period.
|
||||
-- This mechanism is used to reduce the possibility of metastability issues due to differing clocks.
|
||||
-- We only act after both Busy signals are high, thus one SDRAM clock after cpuBusy goes high.
|
||||
sdBusy <= cpuBusy;
|
||||
|
||||
-- If the SDRAM has completed its transaction and the CPU has acknowledged it, remove the signals.
|
||||
if (sdDone = '1' and cpuDoneAck = '1') then
|
||||
sdDone <= '0';
|
||||
end if;
|
||||
|
||||
-- Auto refresh. On timeout it kicks in so that ROWS auto refreshes are
|
||||
-- issued in a tRFC period. Other bus operations are stalled during this period.
|
||||
if (sdRefreshCount > REFRESH_PERIOD and sdCycle = 0) then
|
||||
sdAutoRefresh <= '1';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdCmd <= CMD_PRECHARGE;
|
||||
sdMuxAddr(10) <= '1';
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
|
||||
@@ -299,7 +303,7 @@ begin
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
when CYCLE_RFSH_START =>
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
|
||||
when CYCLE_RFSH_END =>
|
||||
-- reset the count.
|
||||
@@ -308,178 +312,193 @@ begin
|
||||
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
elsif ((sbBusy = '1' and sdCycle = 0) or sdCycle /= 0) then -- or (sdCycle = 0 and CS = '1')) then
|
||||
|
||||
elsif (((cpuBusy = '1' and sdBusy = '1') and sdCycle = 0) or sdCycle /= 0) then
|
||||
|
||||
-- while the cycle is active count.
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
|
||||
when CYCLE_PRECHARGE =>
|
||||
-- If the bank is not open then no need to precharge, move onto RAS.
|
||||
if (sdActiveBank(sdBank) = '0') then
|
||||
if (sdActiveBank(cpuBank) = '0') then
|
||||
sdCycle <= CYCLE_RAS_START;
|
||||
|
||||
-- If the requested row is already active, go to CAS for immediate access to this row.
|
||||
elsif (sdActiveRow(sdBank) = sdRow) then
|
||||
sdCycle <= CYCLE_CAS0;
|
||||
elsif (sdActiveRow(cpuBank) = cpuRow) then
|
||||
sdCycle <= CYCLE_CAS_START;
|
||||
|
||||
-- Otherwise we close out the open bank by issuing a PRECHARGE.
|
||||
else
|
||||
sdCmd <= CMD_PRECHARGE;
|
||||
sdMuxAddr(10) <= '0';
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length));
|
||||
sdActiveBank(sdBank) <= '0'; -- Store flag to indicate which bank is being made active.
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '0';
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length));
|
||||
sdActiveBank(cpuBank) <= '0'; -- Store flag to indicate which bank is being made active.
|
||||
end if;
|
||||
|
||||
-- Open the requested row.
|
||||
when CYCLE_RAS_START =>
|
||||
sdCmd <= CMD_ACTIVE;
|
||||
sdMuxAddr <= sdRow; -- Addr presented to SDRAM as row address.
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length)); -- Addr presented to SDRAM as bank select.
|
||||
sdActiveRow(sdBank) <= sdRow; -- Store number of row being made active
|
||||
sdActiveBank(sdBank) <= '1'; -- Store flag to indicate which bank is being made active.
|
||||
sdCmd := CMD_ACTIVE;
|
||||
SDRAM_ADDR <= cpuRow; -- Addr presented to SDRAM as row address.
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length)); -- Addr presented to SDRAM as bank select.
|
||||
sdActiveRow(cpuBank) <= cpuRow; -- Store number of row being made active
|
||||
sdActiveBank(cpuBank) <= '1'; -- Store flag to indicate which bank is being made active.
|
||||
|
||||
when CYCLE_RAS_NEXT =>
|
||||
sdDQM <= "11"; -- Set DQ to tri--state.
|
||||
|
||||
-- this is the first CAS cycle
|
||||
when CYCLE_CAS0 =>
|
||||
-- Process on a 32bit boundary, as this is a 16bit chip we need 2 accesses for a 32bit alignment.
|
||||
sdMuxAddr <= std_logic_vector(to_unsigned(to_integer(unsigned(sdCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length)); -- Ensure bank is the correct one opened.
|
||||
|
||||
-- CAS start, for 32 bit chips, only 1 CAS cycle is needed, for 16bit chips we need 2 to read/write 2x16bit words.
|
||||
when CYCLE_CAS_START =>
|
||||
|
||||
-- If writing, setup for a write with preset mask.
|
||||
if (sdIsWriting = '1') then
|
||||
sdCmd <= CMD_WRITE;
|
||||
sdDQM <= not cpuDQM(3 downto 2);
|
||||
sdDataOut <= cpuDataIn(31 downto 16); -- Assign corresponding data to the SDRAM databus.
|
||||
if (cpuIsWriting = '1') then
|
||||
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 2) & '0' & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing 32bit data with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn; -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 0);
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn((SDRAM_DATAWIDTH*2)-1 downto SDRAM_DATAWIDTH); -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 2);
|
||||
else
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
sdCmd := CMD_WRITE;
|
||||
|
||||
else
|
||||
-- Setup for a read.
|
||||
sdCmd <= CMD_READ;
|
||||
sdDQM <= "00"; -- For reads dont mask the data output.
|
||||
sdCmd := CMD_READ;
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_DQM <= "00"; -- For reads dont mask the data output.
|
||||
end if;
|
||||
|
||||
when CYCLE_CAS1 =>
|
||||
sdMuxAddr <= std_logic_vector(to_unsigned(to_integer(unsigned(sdCol(SDRAM_COLUMN_BITS-1 downto 1) & '1')), SDRAM_ROW_BITS)); -- CAS address = Next address accessing second 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length)); -- Ensure bank is the correct one opened.
|
||||
when CYCLE_CAS_END =>
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '1')), SDRAM_ROW_BITS)); -- CAS address = Next address accessing second 16bit location within the 32bit external alignment with no auto precharge
|
||||
|
||||
-- If writing, setup for a write with preset mask.
|
||||
if (sdIsWriting = '1') then
|
||||
sdCmd <= CMD_WRITE;
|
||||
sdDQM <= not cpuDQM(1 downto 0);
|
||||
sdDone <= not sdDone;
|
||||
sdDataOut <= cpuDataIn(15 downto 0);
|
||||
sdCycle <= CYCLE_END;
|
||||
-- When writing, setup for a write with preset mask with the correct word.
|
||||
if (cpuIsWriting = '1') then
|
||||
SDRAM_DQM <= not cpuDQM(1 downto 0);
|
||||
SDRAM_DQ <= cpuDataIn(SDRAM_DATAWIDTH-1 downto 0);
|
||||
sdDone <= '1';
|
||||
sdCycle <= CYCLE_END;
|
||||
sdCmd := CMD_WRITE;
|
||||
else
|
||||
-- Setup for a read, change to write if flag set.
|
||||
sdCmd <= CMD_READ;
|
||||
sdDQM <= "00"; -- For reads dont mask the data output.
|
||||
sdCmd := CMD_READ;
|
||||
SDRAM_DQM <= "00"; -- For reads dont mask the data output.
|
||||
end if;
|
||||
|
||||
-- Data is available CAS Latency clocks after the read request.
|
||||
when CYCLE_READ0 =>
|
||||
-- If writing, then we are complete, exit else read the first word.
|
||||
if (sdIsWriting = '1') then
|
||||
-- Data is available CAS Latency clocks after the read request. For 32bit chips, only 1 cycle is needed, for 16bit we need 2 read cycles of
|
||||
-- 16 bits each.
|
||||
when CYCLE_READ_START =>
|
||||
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
sdDataOut <= SDRAM_DQ;
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
sdDataOut((SDRAM_DATAWIDTH*2)-1 downto SDRAM_DATAWIDTH) <= SDRAM_DQ;
|
||||
else
|
||||
dout(31 downto 16) <= sdDataIn;
|
||||
end if;
|
||||
|
||||
when CYCLE_READ1 =>
|
||||
-- If writing, then we are complete, exit else read the first word.
|
||||
if (sdIsWriting = '1') then
|
||||
sdCycle <= CYCLE_END;
|
||||
else
|
||||
dout(15 downto 0) <= sdDataIn;
|
||||
sdDone <= not sdDone;
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
|
||||
-- Second and final read cycle for 16bit SDRAM chips to create a 32bit word.
|
||||
when CYCLE_READ_END =>
|
||||
sdDataOut(SDRAM_DATAWIDTH-1 downto 0) <= SDRAM_DQ;
|
||||
|
||||
when CYCLE_END =>
|
||||
sdDone <= '1';
|
||||
sdCycle <= 0;
|
||||
|
||||
-- Other states are wait states, waiting for the correct time slot for SDRAM access.
|
||||
when others =>
|
||||
end case;
|
||||
else
|
||||
sdCycle <= 0;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- drive control signals according to current command
|
||||
SDRAM_CKE <= sdCmd(4);
|
||||
SDRAM_CS_n <= sdCmd(3);
|
||||
SDRAM_RAS_n <= sdCmd(2);
|
||||
SDRAM_CAS_n <= sdCmd(1);
|
||||
SDRAM_WE_n <= sdCmd(0);
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
-- CPU/BUS side logic. When the CPU initiates a transaction, capture the signals and the captured values are used within the SDRAM domain. This is to prevent
|
||||
|
||||
-- CPU/WishBone side logic. When the CPU initiates a transaction, capture the signals and the captured values are used within the SDRAM domain. This is to prevent
|
||||
-- any changes CPU side or differing signal lengths due to CPU architecture or clock being propogated into the SDRAM domain. The CPU only needs to know
|
||||
-- when the transation is complete and data read.
|
||||
--
|
||||
process(WB_RST_I, WB_CLK, WB_ADR_I, isReady)
|
||||
process(ALL)
|
||||
begin
|
||||
if (WB_RST_I = '1') then
|
||||
sdDoneLast <= '0';
|
||||
sbBusy <= '0';
|
||||
sdBank <= 0;
|
||||
sdRow <= (others => '0');
|
||||
sdCol <= (others => '0');
|
||||
cpuDoneLast <= '0';
|
||||
cpuBusy <= '0';
|
||||
cpuBank <= 0;
|
||||
cpuRow <= (others => '0');
|
||||
cpuCol <= (others => '0');
|
||||
cpuDQM <= (others => '1');
|
||||
sdIsWriting <= '0';
|
||||
cpuDoneAck <= '0';
|
||||
cpuIsWriting <= '0';
|
||||
wbACK <= '0';
|
||||
|
||||
-- If the SDRAM isnt ready, we can only wait.
|
||||
elsif isReady = '0' then
|
||||
-- Wait for the SDRAM to become ready by holding the CPU in a wait state.
|
||||
elsif sdIsReady = '0' then
|
||||
cpuBusy <= '1';
|
||||
|
||||
elsif rising_edge(WB_CLK) then
|
||||
|
||||
-- Detect a Wishbone cycle and commenct an SDRAM access.
|
||||
if (WB_STB_I = '1' and WB_CYC_I = '1' and sbBusy = '0') then
|
||||
sbBusy <= '1';
|
||||
sdIsWriting <= WB_WE_I;
|
||||
sdBank <= to_integer(unsigned(WB_ADR_I(SDRAM_ADDR_BITS-1 downto SDRAM_ARRAY_BITS)));
|
||||
sdRow <= std_logic_vector(to_unsigned(to_integer(unsigned(WB_ADR_I(SDRAM_ARRAY_BITS + 1 - SDRAM_BANK_BITS downto SDRAM_COLUMN_BITS))), SDRAM_ROW_BITS));
|
||||
sdCol <= WB_ADR_I(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
|
||||
-- Detect a Wishbone cycle and commence an SDRAM access.
|
||||
if (WB_STB_I = '1' and WB_CYC_I = '1' and cpuBusy = '0') then
|
||||
cpuBusy <= '1';
|
||||
cpuBank <= to_integer(unsigned(WB_ADR_I(SDRAM_ADDR_BITS-1 downto SDRAM_ARRAY_BITS+1)));
|
||||
cpuRow <= std_logic_vector(to_unsigned(to_integer(unsigned(WB_ADR_I(SDRAM_ARRAY_BITS downto SDRAM_COLUMN_BITS+1))), SDRAM_ROW_BITS));
|
||||
cpuCol <= WB_ADR_I(SDRAM_COLUMN_BITS downto 2) & '0';
|
||||
cpuDQM <= WB_SEL_I;
|
||||
cpuDataIn <= WB_DATA_I;
|
||||
end if;
|
||||
|
||||
if (WB_STB_I = '1' and WB_CYC_I = '1' and cpuBusy = '1') then
|
||||
cpuIsWriting <= WB_WE_I;
|
||||
end if;
|
||||
|
||||
-- Note SDRAM activity via a previous/last signal.
|
||||
sdDoneLast <= sdDone;
|
||||
cpuDoneLast <= sdDone;
|
||||
|
||||
-- If there has been a change in the SDRAM activity and it hasnt been acknowleged, send the ACK else cancel any previous ACK.
|
||||
if (sdDone xor sdDoneLast) = '1' and wbACK = '0' then
|
||||
sbBusy <= '0';
|
||||
sdIsWriting <= '0';
|
||||
-- If there has been a change in the SDRAM activity and it hasnt been acknowleged, send the ACK and use the cycle to latch the retrieved data.
|
||||
if (cpuDoneLast = '0' and sdDone = '1') then
|
||||
cpuDoneAck <= '1';
|
||||
WB_DATA_O <= sdDataOut;
|
||||
end if;
|
||||
|
||||
-- If we are at the end of an active Cycle and the acknowledge to the sdram fsm has been sent, clear all signals and assert the Wishbone Ack to
|
||||
-- complete.
|
||||
if (cpuDoneLast = '1' and sdDone = '0' and cpuDoneAck = '1' and wbACK = '0') then
|
||||
cpuBusy <= '0';
|
||||
cpuDoneAck <= '0';
|
||||
cpuIsWriting <= '0';
|
||||
wbACK <= '1';
|
||||
else
|
||||
wbACK <= '0';
|
||||
end if;
|
||||
|
||||
-- If we are in an active Cycle and the Strobe is activated, assign any read data to the WB bus.
|
||||
if (WB_STB_I = '1' and WB_CYC_I = '1') then
|
||||
|
||||
-- If there has been a change in the SDRAM activity and it hasnt been acknowledged, send the current data held to the WB Bus.
|
||||
if ((sdDone xor sdDoneLast) = '1' and wbACK = '0') then
|
||||
WB_DATA_O <= dout;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- drive control signals according to current command
|
||||
SDRAM_CS_n <= sdCmd(3);
|
||||
SDRAM_RAS_n <= sdCmd(2);
|
||||
SDRAM_CAS_n <= sdCmd(1);
|
||||
SDRAM_WE_n <= sdCmd(0);
|
||||
SDRAM_CKE <= sdCKE;
|
||||
SDRAM_DQM <= sdDQM;
|
||||
SDRAM_ADDR <= sdMuxAddr;
|
||||
SDRAM_READY <= isReady;
|
||||
-- System bus control signals.
|
||||
SDRAM_READY <= sdIsReady;
|
||||
|
||||
-- Wishbone bus control signals.
|
||||
WB_ACK_O <= wbACK;
|
||||
|
||||
--- Throttle
|
||||
WB_HALT_O <= '0';
|
||||
--- Throttle not needed.
|
||||
WB_HALT_O <= '0';
|
||||
|
||||
--- Error
|
||||
WB_ERR_O <= '0';
|
||||
--- Error not yet implemented.
|
||||
WB_ERR_O <= '0';
|
||||
|
||||
end Structure;
|
||||
|
||||
712
devices/WishBone/SDRAM/wbsdram_cached.vhd
Normal file
@@ -0,0 +1,712 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
--
|
||||
-- Name: wbsdram_cached.vhd
|
||||
-- Created: September 2019
|
||||
-- Author: Philip Smart
|
||||
-- Description: A configurable cached sdram controller for use with the ZPU EVO Processor and SoC.
|
||||
-- The module is instantiated with the parameters to describe the underlying SDRAM chip
|
||||
-- and in theory should work with most 16/32 bit SDRAM chips if they adhere to the SDRAM
|
||||
-- standard.
|
||||
-- Credits: Stephen J. Leary 2013-2014 - Basic sdram cycle structure of this module was based on
|
||||
-- the verilog MT48LC16M16 chip controller written by Stephen.
|
||||
-- Copyright: (c) 2019-2020 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: September 2019 - Initial module translation to VHDL based on Stephen J. Leary's Verilog
|
||||
-- source code.
|
||||
-- November 2019 - Adapted for the system bus for use when no Wishbone interface is
|
||||
-- instantiated in the ZPU Evo.
|
||||
-- December 2019 - Extensive changes, metability stability, autorefresh to ACTIVE timing
|
||||
-- and parameterisation.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- This source file is free software: you can redistribute it and-or modify
|
||||
-- it under the terms of the GNU General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This source file is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http:--www.gnu.org-licenses->.
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
library pkgs;
|
||||
library work;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use work.zpu_soc_pkg.all;
|
||||
use work.zpu_pkg.all;
|
||||
|
||||
entity WBSDRAM is
|
||||
generic (
|
||||
MAX_DATACACHE_BITS : integer := 4; -- Maximum size in addr bits of 32bit datacache for burst transactions.
|
||||
SDRAM_ROWS : integer := 4096; -- Number of Rows in the SDRAM.
|
||||
SDRAM_COLUMNS : integer := 256; -- Number of Columns in an SDRAM page (ie. 1 row).
|
||||
SDRAM_BANKS : integer := 4; -- Number of banks in the SDRAM.
|
||||
SDRAM_DATAWIDTH : integer := 16; -- Data width of SDRAM chip (16, 32).
|
||||
SDRAM_CLK_FREQ : integer := 100000000; -- Frequency of the SDRAM clock in Hertz.
|
||||
SDRAM_tRCD : integer := 20; -- tRCD - RAS to CAS minimum period (in ns).
|
||||
SDRAM_tRP : integer := 20; -- tRP - Precharge delay, min time for a precharge command to complete (in ns).
|
||||
SDRAM_tRFC : integer := 70; -- tRFC - Auto-refresh minimum time to complete (in ns), ie. 66ns
|
||||
SDRAM_tREF : integer := 64 -- tREF - period of time a complete refresh of all rows is made within (in ms).
|
||||
);
|
||||
port (
|
||||
-- SDRAM Interface
|
||||
SDRAM_CLK : in std_logic; -- SDRAM is accessed at given clock, frequency specified in RAM_CLK.
|
||||
SDRAM_RST : in std_logic; -- Reset the sdram controller.
|
||||
SDRAM_CKE : out std_logic; -- Clock enable.
|
||||
SDRAM_DQ : inout std_logic_vector(SDRAM_DATAWIDTH-1 downto 0); -- Bidirectional data bus
|
||||
SDRAM_ADDR : out std_logic_vector(log2ceil(SDRAM_ROWS) - 1 downto 0); -- Multiplexed address bus
|
||||
SDRAM_DQM : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of byte masks dependent on number of banks.
|
||||
SDRAM_BA : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of banks in SDRAM
|
||||
SDRAM_CS_n : out std_logic; -- Single chip select
|
||||
SDRAM_WE_n : out std_logic; -- Write enable
|
||||
SDRAM_RAS_n : out std_logic; -- Row address select
|
||||
SDRAM_CAS_n : out std_logic; -- Columns address select
|
||||
SDRAM_READY : out std_logic; -- SD ready.
|
||||
|
||||
-- WishBone interface.
|
||||
WB_CLK : in std_logic; -- Master clock at which the Wishbone interface operates.
|
||||
WB_RST_I : in std_logic; -- high active sync reset
|
||||
WB_DATA_I : in std_logic_vector(WORD_32BIT_RANGE); -- Data input from Master
|
||||
WB_DATA_O : out std_logic_vector(WORD_32BIT_RANGE); -- Data output to Master
|
||||
WB_ACK_O : out std_logic;
|
||||
WB_ADR_I : in std_logic_vector(log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS) downto 0);
|
||||
WB_SEL_I : in std_logic_vector(3 downto 0);
|
||||
WB_CTI_I : in std_logic_vector(2 downto 0); -- 000 Classic cycle, 001 Constant address burst cycle, 010 Incrementing burst cycle, 111 End-of-Burst
|
||||
WB_STB_I : in std_logic;
|
||||
WB_CYC_I : in std_logic; -- cpu/chipset requests cycle
|
||||
WB_WE_I : in std_logic; -- cpu/chipset requests write
|
||||
WB_TGC_I : in std_logic_vector(06 downto 0); -- cycle tag
|
||||
WB_HALT_O : out std_logic; -- throttle master
|
||||
WB_ERR_O : out std_logic -- abnormal cycle termination
|
||||
);
|
||||
end WBSDRAM;
|
||||
|
||||
architecture Structure of WBSDRAM is
|
||||
|
||||
-- Constants to define the structure of the SDRAM in bits for provisioning of signals.
|
||||
constant SDRAM_ROW_BITS : integer := log2ceil(SDRAM_ROWS);
|
||||
constant SDRAM_COLUMN_BITS : integer := log2ceil(SDRAM_COLUMNS);
|
||||
constant SDRAM_ARRAY_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS);
|
||||
constant SDRAM_BANK_BITS : integer := log2ceil(SDRAM_BANKS);
|
||||
constant SDRAM_ADDR_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS * (SDRAM_DATAWIDTH/8));
|
||||
|
||||
-- Command table for a standard SDRAM.
|
||||
--
|
||||
-- Name (Function) CKE CS# RAS# CAS# WE# DQM ADDR DQ
|
||||
-- COMMAND INHIBIT (NOP) H H X X X X X X
|
||||
-- NO OPERATION (NOP) H L H H H X X X
|
||||
-- ACTIVE (select bank and activate row) H L L H H X Bank/row X
|
||||
-- READ (select bank and column, and start READ burst) H L H L H L/H Bank/col X
|
||||
-- WRITE (select bank and column, and start WRITE burst) H L H L L L/H Bank/col Valid
|
||||
-- BURST TERMINATE H L H H L X X Active
|
||||
-- PRECHARGE (Deactivate row in bank or banks) H L L H L X Code X
|
||||
-- AUTO REFRESH or SELF REFRESH (enter self refresh mode) H L L L H X X X
|
||||
-- LOAD MODE REGISTER H L L L L X Op-code X
|
||||
-- Write enable/output enable H X X X X L X Active
|
||||
-- Write inhibit/output High-Z H X X X X H X High-Z
|
||||
-- Self Refresh Entry L L L L H X X X
|
||||
-- Self Refresh Exit (Device is idle) H H X X X X X X
|
||||
-- Self Refresh Exit (Device is in Self Refresh state) H L H H X X X X
|
||||
-- Clock suspend mode Entry L X X X X X X X
|
||||
-- Clock suspend mode Exit H X X X X X X X
|
||||
-- Power down mode Entry (Device is idle) L H X X X X X X
|
||||
-- Power down mode Entry (Device is Active) L L H H X X X X
|
||||
-- Power down mode Exit (Any state) H H X X X X X X
|
||||
-- Power down mode Exit (Device is powered down) H L H H X X X X
|
||||
|
||||
constant CMD_INHIBIT : std_logic_vector(4 downto 0) := "11111";
|
||||
constant CMD_NOP : std_logic_vector(4 downto 0) := "10111";
|
||||
constant CMD_ACTIVE : std_logic_vector(4 downto 0) := "10011";
|
||||
constant CMD_READ : std_logic_vector(4 downto 0) := "10101";
|
||||
constant CMD_WRITE : std_logic_vector(4 downto 0) := "10100";
|
||||
constant CMD_BURST_TERMINATE : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_PRECHARGE : std_logic_vector(4 downto 0) := "10010";
|
||||
constant CMD_AUTO_REFRESH : std_logic_vector(4 downto 0) := "10001";
|
||||
constant CMD_LOAD_MODE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_SELF_REFRESH_START : std_logic_vector(4 downto 0) := "00001";
|
||||
constant CMD_SELF_REFRESH_END : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_CLOCK_SUSPEND : std_logic_vector(4 downto 0) := "00000";
|
||||
constant CMD_CLOCK_RESTORE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_POWER_DOWN : std_logic_vector(4 downto 0) := "01000";
|
||||
constant CMD_POWER_RESTORE : std_logic_vector(4 downto 0) := "01100";
|
||||
|
||||
-- Load Mode Register setting for a standard SDRAM.
|
||||
--
|
||||
-- xx:10 = Reserved :
|
||||
-- 9 = Write Burst Mode : 0 = Programmed Burst Length, 1 = Single Location Access
|
||||
-- 8:7 = Operating Mode : 00 = Standard Operation, all other values reserved.
|
||||
-- 6:4 = CAS Latency : 010 = 2, 011 = 3, all other values reserved.
|
||||
-- 3 = Burst Type : 0 = Sequential, 1 = Interleaved.
|
||||
-- 2:0 = Burst Length : When 000 = 1, 001 = 2, 010 = 4, 011 = 8, all others reserved except 111 when BT = 0 sets full page access.
|
||||
-- | A12-A10 | A9 A8-A7 | A6 A5 A4 | A3Â A2 A1 A0 |
|
||||
-- | reserved| wr burst |reserved| CAS Ltncy|addr mode| burst len|
|
||||
constant WRITE_BURST_MODE : std_logic := '1';
|
||||
constant OP_MODE : std_logic_vector(1 downto 0) := "00";
|
||||
constant CAS_LATENCY : std_logic_vector(2 downto 0) := "011";
|
||||
constant BURST_TYPE : std_logic := '0';
|
||||
constant BURST_LENGTH : std_logic_vector(2 downto 0) := "111";
|
||||
constant MODE : std_logic_vector(SDRAM_ROW_BITS-1 downto 0) := std_logic_vector(to_unsigned(to_integer(unsigned("00" & WRITE_BURST_MODE & OP_MODE & CAS_LATENCY & BURST_TYPE & BURST_LENGTH)), SDRAM_ROW_BITS));
|
||||
|
||||
-- FSM Cycle States governed in units of time, the state changes location according to the configurable parameters to ensure correct actuation at the correct time.
|
||||
--
|
||||
constant CYCLE_PRECHARGE : integer := 0; -- ~0
|
||||
constant CYCLE_RAS_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~3
|
||||
constant CYCLE_CAS_START : integer := CYCLE_RAS_START + clockTicks(SDRAM_tRCD, SDRAM_CLK_FREQ); -- ~3 + tRCD
|
||||
constant CYCLE_WRITE_END : integer := CYCLE_CAS_START + 1; -- ~4 + tRCD
|
||||
constant CYCLE_READ_START : integer := CYCLE_CAS_START + to_integer(unsigned(CAS_LATENCY)) + 1; -- ~3 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_READ_END : integer := CYCLE_READ_START + 1; -- ~4 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_END : integer := CYCLE_READ_END + 1; -- ~9 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_RFSH_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~tRP
|
||||
constant CYCLE_RFSH_END : integer := CYCLE_RFSH_START + clockTicks(SDRAM_tRFC, SDRAM_CLK_FREQ) + clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ) + 1; -- ~tRP (start) + tRFC (min autorefresh time) + tRP (end) in clock ticks.
|
||||
|
||||
-- Period in clock cycles between SDRAM refresh cycles. This equates to tREF / SDRAM_ROWS to evenly divide the time, then subtract the length of the refresh period as this is
|
||||
-- the time it takes when a refresh starts until completion.
|
||||
constant REFRESH_PERIOD : integer := (((SDRAM_tREF * SDRAM_CLK_FREQ ) / SDRAM_ROWS) - (SDRAM_tRFC * 1000)) / 1000;
|
||||
|
||||
-- Array of row addresses, one per bank, to indicate the row in use per bank.
|
||||
type BankArray is array(natural range 0 to SDRAM_BANKS-1) of std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
type BankCacheArray is array(natural range 0 to SDRAM_BANKS-1) of std_logic_vector(((SDRAM_ROW_BITS-1)+SDRAM_BANK_BITS) downto 0);
|
||||
|
||||
-- SDRAM domain signals.
|
||||
signal sdBusy : std_logic;
|
||||
signal sdCycle : integer range 0 to 31;
|
||||
signal sdDone : std_logic;
|
||||
shared variable sdCmd : std_logic_vector(4 downto 0);
|
||||
signal sdRefreshCount : unsigned(11 downto 0);
|
||||
signal sdAutoRefresh : std_logic;
|
||||
signal sdResetTimer : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdInResetCounter : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdIsReady : std_logic;
|
||||
signal sdActiveRow : BankArray;
|
||||
signal sdActiveBank : std_logic_vector(1 downto 0);
|
||||
signal sdWriteColumnAddr : unsigned(SDRAM_COLUMN_BITS-1 downto 0); -- Address at byte level as bit 0 is used as part of the fifo write enable.
|
||||
signal sdWriteCnt : integer range 0 to SDRAM_COLUMNS-1;
|
||||
|
||||
-- CPU domain signals.
|
||||
signal cpuBusy : std_logic;
|
||||
signal cpuDQM : std_logic_vector(3 downto 0);
|
||||
signal cpuBank : natural range 0 to SDRAM_BANKS-1;
|
||||
signal cpuRow : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
signal cpuCol : std_logic_vector(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
signal cpuDataOut : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal cpuDataIn : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal cpuDoneLast : std_logic;
|
||||
signal cpuIsWriting : std_logic;
|
||||
signal cpuLastEN : std_logic;
|
||||
signal cpuCachedBank : std_logic_vector(SDRAM_BANK_BITS-1 downto 0);
|
||||
signal cpuCachedRow : BankCacheArray;
|
||||
signal wbACK : std_logic;
|
||||
|
||||
-- Infer a BRAM array for 4 banks of 16bit words. 32bit is created by 2 arrays.
|
||||
type ramArray is array(natural range 0 to ((SDRAM_COLUMNS/2)*4)-1) of std_logic_vector(WORD_8BIT_RANGE);
|
||||
|
||||
-- Declare the BRAM arrays for 32bit as a set of 4 x 8bit banks.
|
||||
shared variable fifoCache_3 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable fifoCache_2 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable fifoCache_1 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable fifoCache_0 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
-- Fifo control signals.
|
||||
signal fifoDataOutHi : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoDataOutLo : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoDataInHi : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoDataInLo : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoSdWREN_1 : std_logic;
|
||||
signal fifoSdWREN_0 : std_logic;
|
||||
signal fifoCPUWREN_3 : std_logic;
|
||||
signal fifoCPUWREN_2 : std_logic;
|
||||
signal fifoCPUWREN_1 : std_logic;
|
||||
signal fifoCPUWREN_0 : std_logic;
|
||||
begin
|
||||
|
||||
-- Main FSM for SDRAM control and refresh.
|
||||
process(ALL)
|
||||
begin
|
||||
|
||||
if (SDRAM_RST = '1') then
|
||||
sdResetTimer <= (others => '0'); -- 0 upto 127
|
||||
sdInResetCounter <= (others => '1'); -- 255 downto 0
|
||||
sdAutoRefresh <= '0';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
sdIsReady <= '0';
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
SDRAM_DQM <= (others => '1');
|
||||
sdCycle <= 0;
|
||||
sdDone <= '0';
|
||||
fifoSdWREN_0 <= '0';
|
||||
fifoSdWREN_1 <= '0';
|
||||
sdWriteColumnAddr <= (others => '0');
|
||||
|
||||
elsif rising_edge(SDRAM_CLK) then
|
||||
|
||||
-- Write Enables are only 1 clock wide, clear on each cycle.
|
||||
fifoSdWREN_1 <= '0';
|
||||
fifoSdWREN_0 <= '0';
|
||||
|
||||
-- Tri-state control, set the SDRAM databus to tri-state if we are not in write mode.
|
||||
if (cpuIsWriting = '0') then
|
||||
SDRAM_DQ <= (others => 'Z');
|
||||
end if;
|
||||
|
||||
-- If no specific command given the default is NOP.
|
||||
sdCmd := CMD_NOP;
|
||||
|
||||
-- Initialisation on power up or reset. The SDRAM must be given at least 200uS to initialise and a fixed setup pattern applied.
|
||||
if (sdIsReady = '0') then
|
||||
sdResetTimer <= sdResetTimer + 1;
|
||||
|
||||
-- 1uS timer.
|
||||
if (sdResetTimer = SDRAM_CLK_FREQ/1000000) then
|
||||
sdResetTimer <= (others => '0');
|
||||
sdInResetCounter <= sdInResetCounter - 1;
|
||||
end if;
|
||||
|
||||
-- Every 1uS check for the next init action.
|
||||
if (sdResetTimer = 0) then
|
||||
|
||||
-- 200uS wait, no action as the SDRAM starts up.
|
||||
-- ie. 255 downto 55
|
||||
|
||||
-- Precharge all banks
|
||||
if(sdInResetCounter = 55) then
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 40 and sdInResetCounter <= 48) then
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- Load the Mode register with our parameters.
|
||||
if(sdInResetCounter = 39) then
|
||||
sdCmd := CMD_LOAD_MODE;
|
||||
SDRAM_ADDR <= MODE;
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 30 and sdInResetCounter <= 38) then
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- SDRAM ready.
|
||||
if(sdInResetCounter = 20) then
|
||||
sdIsReady <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
else
|
||||
|
||||
-- Counter to time periods between autorefresh.
|
||||
sdRefreshCount <= sdRefreshCount + 1;
|
||||
|
||||
-- This mechanism is used to reduce the possibility of metastability issues due to differing clocks.
|
||||
-- We only act after both Busy signals are high, thus one SDRAM clock after cpuBusy goes high.
|
||||
sdBusy <= cpuBusy;
|
||||
|
||||
-- Auto refresh. On timeout it kicks in so that ROWS auto refreshes are
|
||||
-- issued in a tRFC period. Other bus operations are stalled during this period.
|
||||
if (sdRefreshCount > REFRESH_PERIOD and sdCycle = 0) then
|
||||
sdAutoRefresh <= '1';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
|
||||
-- In auto refresh period.
|
||||
elsif (sdAutoRefresh = '1') then
|
||||
|
||||
-- while the cycle is active count.
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
when CYCLE_RFSH_START =>
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
|
||||
when CYCLE_RFSH_END =>
|
||||
-- reset the count.
|
||||
sdAutoRefresh <= '0';
|
||||
sdCycle <= 0;
|
||||
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
elsif ((cpuBusy = '1' and sdCycle = 0) or sdCycle /= 0) then -- or (sdCycle = 0 and CS = '1')) then
|
||||
|
||||
-- while the cycle is active count.
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
|
||||
when CYCLE_PRECHARGE =>
|
||||
-- If the bank is not open then no need to precharge, move onto RAS.
|
||||
if (sdActiveBank(cpuBank) = '0') then
|
||||
sdCycle <= CYCLE_RAS_START;
|
||||
|
||||
-- If the requested row is already active, go to CAS for immediate access to this row.
|
||||
elsif (sdActiveRow(cpuBank) = cpuRow) then
|
||||
sdCycle <= CYCLE_CAS_START;
|
||||
|
||||
-- Otherwise we close out the open bank by issuing a PRECHARGE.
|
||||
else
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '0';
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length));
|
||||
sdActiveBank(cpuBank) <= '0'; -- Store flag to indicate which bank is being made active.
|
||||
end if;
|
||||
|
||||
-- Open the requested row.
|
||||
when CYCLE_RAS_START =>
|
||||
sdCmd := CMD_ACTIVE;
|
||||
SDRAM_ADDR <= cpuRow; -- Addr presented to SDRAM as row address.
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length)); -- Addr presented to SDRAM as bank select.
|
||||
sdActiveRow(cpuBank) <= cpuRow; -- Store number of row being made active
|
||||
sdActiveBank(cpuBank) <= '1'; -- Store flag to indicate which bank is being made active.
|
||||
|
||||
-- CAS start, for 32 bit chips, only 1 CAS cycle is needed, for 16bit chips we need 2 to read/write 2x16bit words.
|
||||
when CYCLE_CAS_START =>
|
||||
-- If writing, setup for a write with preset mask.
|
||||
if (cpuIsWriting = '1') then
|
||||
sdCmd := CMD_WRITE;
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 2) & '0' & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing 32bit data with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn; -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 0);
|
||||
sdDone <= '1';
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
-- A fake statement used to convince Quartus Prime to infer block ram for the fifo and not use registers.
|
||||
fifoDataInHi <= fifoDataOutHi;
|
||||
fifoDataInLo <= fifoDataOutLo;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn((SDRAM_DATAWIDTH*2)-1 downto SDRAM_DATAWIDTH); -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 2);
|
||||
|
||||
-- A fake statement used to convince Quartus Prime to infer block ram for the fifo and not use registers.
|
||||
fifoDataInHi <= fifoDataOutHi;
|
||||
else
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
|
||||
else
|
||||
-- Setup for a read.
|
||||
sdCmd := CMD_READ;
|
||||
SDRAM_ADDR <= (others => '0');
|
||||
SDRAM_DQM <= "00"; -- For reads dont mask the data output.
|
||||
sdWriteCnt <= SDRAM_COLUMNS-1;
|
||||
sdWriteColumnAddr <= (others => '1');
|
||||
end if;
|
||||
|
||||
-- For writes, this state writes out the second word of a 32bit word if we have a 16bit wide SDRAM chip.
|
||||
--
|
||||
when CYCLE_WRITE_END =>
|
||||
-- When writing, setup for a write with preset mask with the correct word.
|
||||
if (cpuIsWriting = '1') then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '1')), SDRAM_ROW_BITS)); -- CAS address = Next address accessing second 16bit location within the 32bit external alignment with no auto precharge
|
||||
sdCmd := CMD_WRITE;
|
||||
SDRAM_DQM <= not cpuDQM(1 downto 0);
|
||||
SDRAM_DQ <= cpuDataIn(SDRAM_DATAWIDTH-1 downto 0);
|
||||
sdDone <= '1';
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
-- A fake statement used to convince Quartus Prime to infer block ram for the fifo and not use registers.
|
||||
fifoDataInLo <= fifoDataOutLo;
|
||||
end if;
|
||||
|
||||
-- Data is available after CAS Latency (2 or 3) clocks after the read request.
|
||||
-- The data is read as a full page burst, 1 clock per word.
|
||||
when CYCLE_READ_START =>
|
||||
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
fifoSdWREN_1 <= '1';
|
||||
fifoSdWREN_0 <= '1';
|
||||
sdWriteCnt <= sdWriteCnt - 2;
|
||||
sdWriteColumnAddr <= sdWriteColumnAddr + 2;
|
||||
fifoDataInHi <= SDRAM_DQ(WORD_UPPER_16BIT_RANGE);
|
||||
fifoDataInLo <= SDRAM_DQ(WORD_LOWER_16BIT_RANGE);
|
||||
|
||||
if sdWriteCnt > 1 then
|
||||
sdCycle <= CYCLE_READ_START;
|
||||
end if;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
if fifoSdWREN_1 = '0' then
|
||||
fifoSdWREN_1 <= '1';
|
||||
fifoDataInHi <= SDRAM_DQ;
|
||||
else
|
||||
fifoSdWREN_0 <= '1';
|
||||
fifoDataInLo <= SDRAM_DQ;
|
||||
end if;
|
||||
sdWriteCnt <= sdWriteCnt - 1;
|
||||
sdWriteColumnAddr <= sdWriteColumnAddr + 1;
|
||||
|
||||
if sdWriteCnt > 0 then
|
||||
sdCycle <= CYCLE_READ_START;
|
||||
end if;
|
||||
|
||||
else
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
|
||||
when CYCLE_READ_END =>
|
||||
sdDone <= '1';
|
||||
|
||||
when CYCLE_END =>
|
||||
sdCycle <= 0;
|
||||
sdDone <= '0';
|
||||
|
||||
-- Other states are wait states, waiting for the correct time slot for SDRAM access.
|
||||
when others =>
|
||||
end case;
|
||||
else
|
||||
sdCycle <= 0;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- drive control signals according to current command
|
||||
SDRAM_CKE <= sdCmd(4);
|
||||
SDRAM_CS_n <= sdCmd(3);
|
||||
SDRAM_RAS_n <= sdCmd(2);
|
||||
SDRAM_CAS_n <= sdCmd(1);
|
||||
SDRAM_WE_n <= sdCmd(0);
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- CPU/BUS side logic. When the CPU initiates a transaction, capture the signals and the captured values are used within the SDRAM domain. This is to prevent
|
||||
-- any changes CPU side or differing signal lengths due to CPU architecture or clock being propogated into the SDRAM domain. The CPU only needs to know
|
||||
-- when the transation is complete and data read.
|
||||
--
|
||||
process(ALL)
|
||||
variable bank : std_logic_vector(1 downto 0);
|
||||
variable row : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
variable writeThru : std_logic;
|
||||
begin
|
||||
|
||||
-- Setup the bank and row as variables to make code reading easier.
|
||||
bank := WB_ADR_I(SDRAM_ADDR_BITS-1) & WB_ADR_I((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1));
|
||||
row := WB_ADR_I(SDRAM_ADDR_BITS-2 downto (SDRAM_COLUMN_BITS+SDRAM_BANK_BITS));
|
||||
|
||||
-- For write operations, if the cached page row for the current bank is the same as the row given by the cpu then we write to both the SDRAM and to the cache.
|
||||
if cpuCachedBank(to_integer(unsigned(bank))) = '1' and cpuCachedRow(to_integer(unsigned(bank))) = WB_ADR_I(SDRAM_ADDR_BITS-1) & WB_ADR_I((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1)) & row then
|
||||
writeThru := '1';
|
||||
else
|
||||
writeThru := '0';
|
||||
end if;
|
||||
|
||||
-- Setup signals to initial state, critical they start at the right values.
|
||||
if (WB_RST_I = '1') then
|
||||
cpuDoneLast <= '0';
|
||||
cpuBusy <= '0';
|
||||
cpuBank <= 0;
|
||||
cpuRow <= (others => '0');
|
||||
cpuCol <= (others => '0');
|
||||
cpuDQM <= (others => '1');
|
||||
cpuLastEN <= '0';
|
||||
cpuCachedBank <= (others => '0');
|
||||
cpuCachedRow <= ( others => (others => '0') );
|
||||
cpuIsWriting <= '0';
|
||||
fifoCPUWREN_3 <= '0';
|
||||
fifoCPUWREN_2 <= '0';
|
||||
fifoCPUWREN_1 <= '0';
|
||||
fifoCPUWREN_0 <= '0';
|
||||
wbACK <= '0';
|
||||
|
||||
-- Wait for the SDRAM to become ready by holding the CPU in a wait state.
|
||||
elsif sdIsReady = '0' then
|
||||
cpuBusy <= '1';
|
||||
|
||||
elsif rising_edge(WB_CLK) then
|
||||
|
||||
-- CPU Cache writes are only 1 cycle wide, so clear any asserted write.
|
||||
fifoCPUWREN_3 <= '0';
|
||||
fifoCPUWREN_2 <= '0';
|
||||
fifoCPUWREN_1 <= '0';
|
||||
fifoCPUWREN_0 <= '0';
|
||||
|
||||
if wbACK = '1' then
|
||||
wbACK <= '0';
|
||||
end if;
|
||||
|
||||
-- Detect a Wishbone cycle and commence an SDRAM access.
|
||||
if (WB_STB_I = '1' and WB_CYC_I = '1' and cpuBusy = '0' and wbACK = '0') then
|
||||
|
||||
-- Organisation of the memory is as follows:
|
||||
--
|
||||
-- Bank: [(SDRAM_ADDR_BITS-1) .. (SDRAM_ADDR_BITS-1)] & [((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) .. (SDRAM_COLUMN_BITS+1)]
|
||||
-- Row: [(SDRAM_ADDR_BITS-2) .. (SDRAM_COLUMN_BITS+SDRAM_BANK_BITS)]
|
||||
-- Column: [(SDRAM_COLUMN_BITS downto 2)]
|
||||
-- The bank is split so that the Bank MSB splits the SDRAM in 2, upper and lower segment, this is because Stack normally resides in the top upper
|
||||
-- segment and code in the bottom lower segment. The remaining bank bits are split at the page level such that 2 or more pages residing in different
|
||||
-- banks are contiguous, hoping to gain a little performance benefit through having a wider spread for code caching and stack caching and write thru.
|
||||
--
|
||||
cpuBank <= to_integer(unsigned(bank));
|
||||
cpuRow <= row;
|
||||
cpuCol <= WB_ADR_I(SDRAM_COLUMN_BITS downto 2) & '0';
|
||||
cpuDQM <= WB_SEL_I;
|
||||
cpuDataIn <= WB_DATA_I;
|
||||
|
||||
-- For write operations, we write direct to memory. If the data is in cache then a write-thru is performed to preserve the cached bank.
|
||||
if WB_WE_I = '1' then
|
||||
|
||||
-- If we are writing to a cached page, update the changed bytes in cache.
|
||||
if writeThru = '1' then
|
||||
if WB_SEL_I(0) then
|
||||
fifoCPUWREN_0 <= '1';
|
||||
end if;
|
||||
if WB_SEL_I(1) then
|
||||
fifoCPUWREN_1 <= '1';
|
||||
end if;
|
||||
if WB_SEL_I(2) then
|
||||
fifoCPUWREN_2 <= '1';
|
||||
end if;
|
||||
if WB_SEL_I(3) then
|
||||
fifoCPUWREN_3 <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Set the flags, cpuBusy indicates to the SDRAM FSM to perform an operation.
|
||||
cpuIsWriting <= WB_WE_I;
|
||||
cpuBusy <= '1';
|
||||
|
||||
-- For reads, if the row is cached then we just fall through to perform a read operation from cache otherwise the
|
||||
-- SDRAM needs to be instructed to read a page into cache before reading.
|
||||
--
|
||||
elsif cpuCachedBank(to_integer(unsigned(bank))) = '0' or cpuCachedRow(to_integer(unsigned(bank))) /= WB_ADR_I(SDRAM_ADDR_BITS-1) & WB_ADR_I((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1)) & row then
|
||||
|
||||
cpuCachedBank(to_integer(unsigned(bank))) <= '1';
|
||||
cpuCachedRow (to_integer(unsigned(bank))) <= WB_ADR_I(SDRAM_ADDR_BITS-1) & WB_ADR_I((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1)) & row;
|
||||
|
||||
-- Set the flags, cpuBusy indicates to the SDRAM FSM to perform an operation.
|
||||
cpuBusy <= '1';
|
||||
|
||||
else
|
||||
wbACK <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Note SDRAM activity via a previous/last signal.
|
||||
cpuDoneLast <= sdDone;
|
||||
|
||||
-- A change in the Done signal then we end the SDRAM request and release the CPU.
|
||||
if cpuDoneLast = '1' and sdDone = '0' then
|
||||
cpuBusy <= '0';
|
||||
cpuIsWriting <= '0';
|
||||
wbACK <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- System bus control signals.
|
||||
SDRAM_READY <= sdIsReady;
|
||||
|
||||
-- Wishbone bus control signals.
|
||||
WB_ACK_O <= wbACK;
|
||||
|
||||
--- Throttle not needed.
|
||||
WB_HALT_O <= '0';
|
||||
|
||||
--- Error not yet implemented.
|
||||
WB_ERR_O <= '0';
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
-- Inferred Dual Port RAM.
|
||||
--
|
||||
-- The dual port ram is used to buffer a full page within the SDRAM, one buffer for each bank. The addressing is such
|
||||
-- that half of the banks appear in the lower segment of the address space and half in the top segment, the MSB of the
|
||||
-- SDRAM address is used for the split. This is to cater for stack where typically, on the ZPU, the stack would reside
|
||||
-- in the very top of memory working down and the applications would reside at the bottom of the memory working up.
|
||||
--
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- SDRAM Side of dual port RAM.
|
||||
-- For Read: fifoDataOutHi <= fifoCache_3(sdWriteColumnAddr)
|
||||
-- fifoDataOutLo <= fifoCache_0(sdWriteColumnAddr)
|
||||
-- For Write: fifoCache_3 _1 <= fifoDataIn when sdWriteColumnAddr(0) = '0'
|
||||
-- fifoCache_2 _0 <= fifoDataIn when sdWriteColumnAddr(0) = '1'
|
||||
-- fifoSdWREN must be asserted ('1') for write operations.
|
||||
process(ALL)
|
||||
variable cacheAddr : unsigned(SDRAM_COLUMN_BITS-2+SDRAM_BANK_BITS downto 0);
|
||||
begin
|
||||
-- Setup the address based on the index (sdWriteColumnAddr) and the bank (cpuBank) as the cache is linear for 4 banks.
|
||||
--
|
||||
cacheAddr := to_unsigned(cpuBank, SDRAM_BANK_BITS) & sdWriteColumnAddr(SDRAM_COLUMN_BITS-1 downto 1);
|
||||
|
||||
if rising_edge(SDRAM_CLK) then
|
||||
if fifoSdWREN_1 = '1' then
|
||||
fifoCache_3(to_integer(cacheAddr)) := fifoDataInHi(WORD_UPPER_16BIT_RANGE);
|
||||
fifoCache_2(to_integer(cacheAddr)) := fifoDataInHi(WORD_LOWER_16BIT_RANGE);
|
||||
else
|
||||
fifoDataOutHi(WORD_UPPER_16BIT_RANGE) <= fifoCache_3(to_integer(cacheAddr));
|
||||
fifoDataOutHi(WORD_LOWER_16BIT_RANGE) <= fifoCache_2(to_integer(cacheAddr));
|
||||
end if;
|
||||
|
||||
if fifoSdWREN_0 = '1' then
|
||||
fifoCache_1(to_integer(cacheAddr)) := fifoDataInLo(WORD_UPPER_16BIT_RANGE);
|
||||
fifoCache_0(to_integer(cacheAddr)) := fifoDataInLo(WORD_LOWER_16BIT_RANGE);
|
||||
else
|
||||
fifoDataOutLo(WORD_UPPER_16BIT_RANGE) <= fifoCache_1(to_integer(cacheAddr));
|
||||
fifoDataOutLo(WORD_LOWER_16BIT_RANGE) <= fifoCache_0(to_integer(cacheAddr));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- CPU Side of dual port RAM, byte addressable.
|
||||
-- For Read: DATA_OUT <= fifoCache(bank + ADDR(COLUMN_BITS .. 2))
|
||||
-- For Write: fifoCache(0..3) <= cpuDataIn
|
||||
process(ALL)
|
||||
variable cacheAddr : unsigned(SDRAM_COLUMN_BITS-2+SDRAM_BANK_BITS downto 0);
|
||||
begin
|
||||
-- Setup the address based on the column address bits, 32 bit aligned and the bank (cpuBank) as the cache is linear for 4 banks.
|
||||
--
|
||||
cacheAddr := to_unsigned(cpuBank, SDRAM_BANK_BITS) & unsigned(WB_ADR_I(SDRAM_COLUMN_BITS downto 2));
|
||||
|
||||
if rising_edge(WB_CLK) then
|
||||
if fifoCPUWREN_3 = '1' then
|
||||
fifoCache_3(to_integer(cacheAddr)) := cpuDataIn(31 downto 24);
|
||||
else
|
||||
WB_DATA_O((SDRAM_DATAWIDTH*2)-1 downto ((SDRAM_DATAWIDTH*2)-(SDRAM_DATAWIDTH/2)))<= fifoCache_3(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
|
||||
if fifoCPUWREN_2 = '1' then
|
||||
fifoCache_2(to_integer(cacheAddr)) := cpuDataIn(23 downto 16);
|
||||
else
|
||||
WB_DATA_O(((SDRAM_DATAWIDTH*2)-(SDRAM_DATAWIDTH/2))-1 downto SDRAM_DATAWIDTH) <= fifoCache_2(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
|
||||
if fifoCPUWREN_1 = '1' then
|
||||
fifoCache_1(to_integer(cacheAddr)) := cpuDataIn(15 downto 8);
|
||||
else
|
||||
WB_DATA_O(SDRAM_DATAWIDTH-1 downto SDRAM_DATAWIDTH/2) <= fifoCache_1(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
|
||||
if fifoCPUWREN_0 = '1' then
|
||||
fifoCache_0(to_integer(cacheAddr)) := cpuDataIn(7 downto 0);
|
||||
else
|
||||
WB_DATA_O((SDRAM_DATAWIDTH/2)-1 downto 0) <= fifoCache_0(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end Structure;
|
||||
@@ -46,10 +46,10 @@ port (
|
||||
clk : in std_logic;
|
||||
areset : in std_logic := '0';
|
||||
memAWriteEnable : in std_logic;
|
||||
memAAddr : in std_logic_vector(ADDR_BIT_BRAM_32BIT_RANGE);
|
||||
memAAddr : in std_logic_vector(ADDR_32BIT_BRAM_RANGE);
|
||||
memAWrite : in std_logic_vector(WORD_32BIT_RANGE);
|
||||
memBWriteEnable : in std_logic;
|
||||
memBAddr : in std_logic_vector(ADDR_BIT_BRAM_32BIT_RANGE);
|
||||
memBAddr : in std_logic_vector(ADDR_32BIT_BRAM_RANGE);
|
||||
memBWrite : in std_logic_vector(WORD_32BIT_RANGE);
|
||||
memARead : out std_logic_vector(WORD_32BIT_RANGE);
|
||||
memBRead : out std_logic_vector(WORD_32BIT_RANGE)
|
||||
@@ -224,7 +224,7 @@ shared variable ram : ram_type :=
|
||||
159 => x"00000000",
|
||||
160 => x"71fc0608",
|
||||
161 => x"0b0b0b9f",
|
||||
162 => x"88738306",
|
||||
162 => x"cc738306",
|
||||
163 => x"10100508",
|
||||
164 => x"060b0b0b",
|
||||
165 => x"88ac0400",
|
||||
@@ -344,8 +344,8 @@ shared variable ram : ram_type :=
|
||||
279 => x"51535104",
|
||||
280 => x"80040088",
|
||||
281 => x"e2040000",
|
||||
282 => x"009fac70",
|
||||
283 => x"9fdc278b",
|
||||
282 => x"009ff070",
|
||||
283 => x"a0a0278b",
|
||||
284 => x"38807170",
|
||||
285 => x"8405530c",
|
||||
286 => x"88eb0488",
|
||||
@@ -515,14 +515,14 @@ shared variable ram : ram_type :=
|
||||
450 => x"8c085170",
|
||||
451 => x"802e8838",
|
||||
452 => x"710b0b0b",
|
||||
453 => x"9fa8340b",
|
||||
454 => x"0b0b9fa8",
|
||||
453 => x"9fec340b",
|
||||
454 => x"0b0b9fec",
|
||||
455 => x"33880c83",
|
||||
456 => x"3d0d04fa",
|
||||
457 => x"3d0d787b",
|
||||
458 => x"7d565856",
|
||||
459 => x"800b0b0b",
|
||||
460 => x"0b9fa833",
|
||||
460 => x"0b9fec33",
|
||||
461 => x"81065255",
|
||||
462 => x"82527075",
|
||||
463 => x"2e098106",
|
||||
@@ -585,7 +585,7 @@ shared variable ram : ram_type :=
|
||||
520 => x"52853d0d",
|
||||
521 => x"04f93d0d",
|
||||
522 => x"790b0b0b",
|
||||
523 => x"9fac0857",
|
||||
523 => x"9ff00857",
|
||||
524 => x"57817727",
|
||||
525 => x"80ed3876",
|
||||
526 => x"88170827",
|
||||
@@ -618,7 +618,7 @@ shared variable ram : ram_type :=
|
||||
553 => x"5574880c",
|
||||
554 => x"893d0d04",
|
||||
555 => x"fb3d0d0b",
|
||||
556 => x"0b0b9fac",
|
||||
556 => x"0b0b9ff0",
|
||||
557 => x"08fe1988",
|
||||
558 => x"1208fe05",
|
||||
559 => x"55565480",
|
||||
@@ -631,7 +631,7 @@ shared variable ram : ram_type :=
|
||||
566 => x"04fd3d0d",
|
||||
567 => x"7554800b",
|
||||
568 => x"0b0b0b9f",
|
||||
569 => x"ac087033",
|
||||
569 => x"f0087033",
|
||||
570 => x"51535371",
|
||||
571 => x"832e0981",
|
||||
572 => x"068c3894",
|
||||
@@ -644,7 +644,7 @@ shared variable ram : ram_type :=
|
||||
579 => x"880c853d",
|
||||
580 => x"0d04fc3d",
|
||||
581 => x"0d760b0b",
|
||||
582 => x"0b9fac08",
|
||||
582 => x"0b9ff008",
|
||||
583 => x"55558075",
|
||||
584 => x"23881508",
|
||||
585 => x"5372812e",
|
||||
@@ -666,7 +666,7 @@ shared variable ram : ram_type :=
|
||||
601 => x"71880c86",
|
||||
602 => x"3d0d04fa",
|
||||
603 => x"3d0d780b",
|
||||
604 => x"0b0b9fac",
|
||||
604 => x"0b0b9ff0",
|
||||
605 => x"08712281",
|
||||
606 => x"057083ff",
|
||||
607 => x"ff065754",
|
||||
@@ -840,7 +840,7 @@ shared variable ram : ram_type :=
|
||||
775 => x"04ed3d0d",
|
||||
776 => x"6559800b",
|
||||
777 => x"0b0b0b9f",
|
||||
778 => x"ac0cf59b",
|
||||
778 => x"f00cf59b",
|
||||
779 => x"3f880881",
|
||||
780 => x"06558256",
|
||||
781 => x"7482f238",
|
||||
@@ -935,11 +935,11 @@ shared variable ram : ram_type :=
|
||||
870 => x"1b0c5580",
|
||||
871 => x"0b811a34",
|
||||
872 => x"780b0b0b",
|
||||
873 => x"9fac0c80",
|
||||
873 => x"9ff00c80",
|
||||
874 => x"5675880c",
|
||||
875 => x"953d0d04",
|
||||
876 => x"ea3d0d0b",
|
||||
877 => x"0b0b9fac",
|
||||
877 => x"0b0b9ff0",
|
||||
878 => x"08558554",
|
||||
879 => x"74802e80",
|
||||
880 => x"df38800b",
|
||||
@@ -970,7 +970,7 @@ shared variable ram : ram_type :=
|
||||
905 => x"3d0d04f6",
|
||||
906 => x"3d0d7d7f",
|
||||
907 => x"7e0b0b0b",
|
||||
908 => x"9fac0859",
|
||||
908 => x"9ff00859",
|
||||
909 => x"5b5c5880",
|
||||
910 => x"7b0c8557",
|
||||
911 => x"75802e81",
|
||||
@@ -1029,42 +1029,59 @@ shared variable ram : ram_type :=
|
||||
964 => x"80577688",
|
||||
965 => x"0c8c3d0d",
|
||||
966 => x"04fb3d0d",
|
||||
967 => x"9b9086e4",
|
||||
968 => x"0b87c094",
|
||||
969 => x"8c0c9b90",
|
||||
970 => x"86e40b87",
|
||||
971 => x"c0949c0c",
|
||||
972 => x"8c80830b",
|
||||
973 => x"87c09484",
|
||||
974 => x"0c8c8083",
|
||||
975 => x"0b87c094",
|
||||
976 => x"940c9fb0",
|
||||
977 => x"51f9d63f",
|
||||
978 => x"8808b838",
|
||||
979 => x"9f9851fc",
|
||||
980 => x"df3f8808",
|
||||
981 => x"ae38a080",
|
||||
982 => x"0b880887",
|
||||
983 => x"c098880c",
|
||||
984 => x"55873dfc",
|
||||
985 => x"05538480",
|
||||
986 => x"527451fd",
|
||||
987 => x"ba3f8808",
|
||||
988 => x"8d387554",
|
||||
989 => x"73802e86",
|
||||
990 => x"38731555",
|
||||
991 => x"e439a080",
|
||||
992 => x"54730480",
|
||||
993 => x"54fb3900",
|
||||
994 => x"00ffffff",
|
||||
995 => x"ff00ffff",
|
||||
996 => x"ffff00ff",
|
||||
997 => x"ffffff00",
|
||||
998 => x"424f4f54",
|
||||
999 => x"54494e59",
|
||||
1000 => x"2e524f4d",
|
||||
1001 => x"00000000",
|
||||
1002 => x"01000000",
|
||||
967 => x"87c0948c",
|
||||
968 => x"08548784",
|
||||
969 => x"80527351",
|
||||
970 => x"ead73f88",
|
||||
971 => x"08902b87",
|
||||
972 => x"c0948c08",
|
||||
973 => x"56548784",
|
||||
974 => x"80527451",
|
||||
975 => x"eac33f73",
|
||||
976 => x"88080787",
|
||||
977 => x"c0948c0c",
|
||||
978 => x"87c0949c",
|
||||
979 => x"08548784",
|
||||
980 => x"80527351",
|
||||
981 => x"eaab3f88",
|
||||
982 => x"08902b87",
|
||||
983 => x"c0949c08",
|
||||
984 => x"56548784",
|
||||
985 => x"80527451",
|
||||
986 => x"ea973f73",
|
||||
987 => x"88080787",
|
||||
988 => x"c0949c0c",
|
||||
989 => x"8c80830b",
|
||||
990 => x"87c09484",
|
||||
991 => x"0c8c8083",
|
||||
992 => x"0b87c094",
|
||||
993 => x"940c9ff4",
|
||||
994 => x"51f9923f",
|
||||
995 => x"8808b838",
|
||||
996 => x"9fdc51fc",
|
||||
997 => x"9b3f8808",
|
||||
998 => x"ae38a080",
|
||||
999 => x"0b880887",
|
||||
1000 => x"c098880c",
|
||||
1001 => x"55873dfc",
|
||||
1002 => x"05538480",
|
||||
1003 => x"527451fc",
|
||||
1004 => x"f63f8808",
|
||||
1005 => x"8d387554",
|
||||
1006 => x"73802e86",
|
||||
1007 => x"38731555",
|
||||
1008 => x"e439a080",
|
||||
1009 => x"54730480",
|
||||
1010 => x"54fb3900",
|
||||
1011 => x"00ffffff",
|
||||
1012 => x"ff00ffff",
|
||||
1013 => x"ffff00ff",
|
||||
1014 => x"ffffff00",
|
||||
1015 => x"424f4f54",
|
||||
1016 => x"54494e59",
|
||||
1017 => x"2e524f4d",
|
||||
1018 => x"00000000",
|
||||
1019 => x"01000000",
|
||||
others => x"00000000"
|
||||
);
|
||||
|
||||
@@ -1078,10 +1095,10 @@ begin
|
||||
end if;
|
||||
|
||||
if (memAWriteEnable = '1') then
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE)))) := memAWrite;
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE)))) := memAWrite;
|
||||
memARead <= memAWrite;
|
||||
else
|
||||
memARead <= ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE))));
|
||||
memARead <= ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
@@ -1090,10 +1107,10 @@ process (clk)
|
||||
begin
|
||||
if (clk'event and clk = '1') then
|
||||
if (memBWriteEnable = '1') then
|
||||
ram(to_integer(unsigned(memBAddr(ADDR_BIT_BRAM_32BIT_RANGE)))) := memBWrite;
|
||||
ram(to_integer(unsigned(memBAddr(ADDR_32BIT_BRAM_RANGE)))) := memBWrite;
|
||||
memBRead <= memBWrite;
|
||||
else
|
||||
memBRead <= ram(to_integer(unsigned(memBAddr(ADDR_BIT_BRAM_32BIT_RANGE))));
|
||||
memBRead <= ram(to_integer(unsigned(memBAddr(ADDR_32BIT_BRAM_RANGE))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
@@ -522,7 +522,7 @@ architecture arch of DualPortBootBRAM is
|
||||
451 => x"38",
|
||||
452 => x"0b",
|
||||
453 => x"0b",
|
||||
454 => x"a8",
|
||||
454 => x"ec",
|
||||
455 => x"83",
|
||||
456 => x"fa",
|
||||
457 => x"7b",
|
||||
@@ -624,7 +624,7 @@ architecture arch of DualPortBootBRAM is
|
||||
553 => x"0c",
|
||||
554 => x"04",
|
||||
555 => x"0b",
|
||||
556 => x"ac",
|
||||
556 => x"f0",
|
||||
557 => x"88",
|
||||
558 => x"05",
|
||||
559 => x"80",
|
||||
@@ -672,7 +672,7 @@ architecture arch of DualPortBootBRAM is
|
||||
601 => x"86",
|
||||
602 => x"fa",
|
||||
603 => x"0b",
|
||||
604 => x"ac",
|
||||
604 => x"f0",
|
||||
605 => x"81",
|
||||
606 => x"ff",
|
||||
607 => x"54",
|
||||
@@ -945,7 +945,7 @@ architecture arch of DualPortBootBRAM is
|
||||
874 => x"0c",
|
||||
875 => x"04",
|
||||
876 => x"0b",
|
||||
877 => x"ac",
|
||||
877 => x"f0",
|
||||
878 => x"54",
|
||||
879 => x"80",
|
||||
880 => x"0b",
|
||||
@@ -1035,42 +1035,59 @@ architecture arch of DualPortBootBRAM is
|
||||
964 => x"88",
|
||||
965 => x"0d",
|
||||
966 => x"0d",
|
||||
967 => x"e4",
|
||||
968 => x"94",
|
||||
969 => x"90",
|
||||
970 => x"87",
|
||||
971 => x"0c",
|
||||
972 => x"0b",
|
||||
967 => x"8c",
|
||||
968 => x"84",
|
||||
969 => x"51",
|
||||
970 => x"88",
|
||||
971 => x"87",
|
||||
972 => x"08",
|
||||
973 => x"84",
|
||||
974 => x"83",
|
||||
975 => x"94",
|
||||
976 => x"b0",
|
||||
977 => x"3f",
|
||||
978 => x"38",
|
||||
979 => x"fc",
|
||||
980 => x"08",
|
||||
981 => x"80",
|
||||
974 => x"51",
|
||||
975 => x"73",
|
||||
976 => x"87",
|
||||
977 => x"0c",
|
||||
978 => x"9c",
|
||||
979 => x"84",
|
||||
980 => x"51",
|
||||
981 => x"88",
|
||||
982 => x"87",
|
||||
983 => x"0c",
|
||||
984 => x"fc",
|
||||
985 => x"80",
|
||||
986 => x"fd",
|
||||
987 => x"08",
|
||||
988 => x"54",
|
||||
989 => x"86",
|
||||
990 => x"55",
|
||||
991 => x"80",
|
||||
992 => x"80",
|
||||
993 => x"00",
|
||||
994 => x"ff",
|
||||
995 => x"ff",
|
||||
996 => x"ff",
|
||||
997 => x"00",
|
||||
998 => x"54",
|
||||
999 => x"59",
|
||||
1000 => x"4d",
|
||||
1001 => x"00",
|
||||
1002 => x"00",
|
||||
983 => x"08",
|
||||
984 => x"84",
|
||||
985 => x"51",
|
||||
986 => x"73",
|
||||
987 => x"87",
|
||||
988 => x"0c",
|
||||
989 => x"0b",
|
||||
990 => x"84",
|
||||
991 => x"83",
|
||||
992 => x"94",
|
||||
993 => x"f4",
|
||||
994 => x"3f",
|
||||
995 => x"38",
|
||||
996 => x"fc",
|
||||
997 => x"08",
|
||||
998 => x"80",
|
||||
999 => x"87",
|
||||
1000 => x"0c",
|
||||
1001 => x"fc",
|
||||
1002 => x"80",
|
||||
1003 => x"fc",
|
||||
1004 => x"08",
|
||||
1005 => x"54",
|
||||
1006 => x"86",
|
||||
1007 => x"55",
|
||||
1008 => x"80",
|
||||
1009 => x"80",
|
||||
1010 => x"00",
|
||||
1011 => x"ff",
|
||||
1012 => x"ff",
|
||||
1013 => x"ff",
|
||||
1014 => x"00",
|
||||
1015 => x"54",
|
||||
1016 => x"59",
|
||||
1017 => x"4d",
|
||||
1018 => x"00",
|
||||
1019 => x"00",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
@@ -1358,7 +1375,7 @@ architecture arch of DualPortBootBRAM is
|
||||
279 => x"51",
|
||||
280 => x"00",
|
||||
281 => x"00",
|
||||
282 => x"ac",
|
||||
282 => x"f0",
|
||||
283 => x"27",
|
||||
284 => x"71",
|
||||
285 => x"53",
|
||||
@@ -1536,7 +1553,7 @@ architecture arch of DualPortBootBRAM is
|
||||
457 => x"78",
|
||||
458 => x"58",
|
||||
459 => x"0b",
|
||||
460 => x"a8",
|
||||
460 => x"ec",
|
||||
461 => x"52",
|
||||
462 => x"70",
|
||||
463 => x"81",
|
||||
@@ -1658,7 +1675,7 @@ architecture arch of DualPortBootBRAM is
|
||||
579 => x"85",
|
||||
580 => x"fc",
|
||||
581 => x"0b",
|
||||
582 => x"ac",
|
||||
582 => x"f0",
|
||||
583 => x"80",
|
||||
584 => x"15",
|
||||
585 => x"81",
|
||||
@@ -2043,42 +2060,59 @@ architecture arch of DualPortBootBRAM is
|
||||
964 => x"76",
|
||||
965 => x"3d",
|
||||
966 => x"3d",
|
||||
967 => x"86",
|
||||
968 => x"c0",
|
||||
969 => x"9b",
|
||||
970 => x"0b",
|
||||
971 => x"9c",
|
||||
972 => x"83",
|
||||
973 => x"94",
|
||||
974 => x"80",
|
||||
975 => x"c0",
|
||||
976 => x"9f",
|
||||
977 => x"d6",
|
||||
978 => x"b8",
|
||||
979 => x"51",
|
||||
980 => x"88",
|
||||
981 => x"a0",
|
||||
982 => x"08",
|
||||
983 => x"88",
|
||||
984 => x"3d",
|
||||
985 => x"84",
|
||||
986 => x"51",
|
||||
987 => x"88",
|
||||
988 => x"75",
|
||||
989 => x"2e",
|
||||
990 => x"15",
|
||||
991 => x"a0",
|
||||
992 => x"04",
|
||||
993 => x"39",
|
||||
994 => x"ff",
|
||||
995 => x"ff",
|
||||
996 => x"00",
|
||||
997 => x"ff",
|
||||
998 => x"4f",
|
||||
999 => x"4e",
|
||||
1000 => x"4f",
|
||||
1001 => x"00",
|
||||
1002 => x"00",
|
||||
967 => x"94",
|
||||
968 => x"87",
|
||||
969 => x"73",
|
||||
970 => x"3f",
|
||||
971 => x"2b",
|
||||
972 => x"8c",
|
||||
973 => x"87",
|
||||
974 => x"74",
|
||||
975 => x"3f",
|
||||
976 => x"07",
|
||||
977 => x"8c",
|
||||
978 => x"94",
|
||||
979 => x"87",
|
||||
980 => x"73",
|
||||
981 => x"3f",
|
||||
982 => x"2b",
|
||||
983 => x"9c",
|
||||
984 => x"87",
|
||||
985 => x"74",
|
||||
986 => x"3f",
|
||||
987 => x"07",
|
||||
988 => x"9c",
|
||||
989 => x"83",
|
||||
990 => x"94",
|
||||
991 => x"80",
|
||||
992 => x"c0",
|
||||
993 => x"9f",
|
||||
994 => x"92",
|
||||
995 => x"b8",
|
||||
996 => x"51",
|
||||
997 => x"88",
|
||||
998 => x"a0",
|
||||
999 => x"08",
|
||||
1000 => x"88",
|
||||
1001 => x"3d",
|
||||
1002 => x"84",
|
||||
1003 => x"51",
|
||||
1004 => x"88",
|
||||
1005 => x"75",
|
||||
1006 => x"2e",
|
||||
1007 => x"15",
|
||||
1008 => x"a0",
|
||||
1009 => x"04",
|
||||
1010 => x"39",
|
||||
1011 => x"ff",
|
||||
1012 => x"ff",
|
||||
1013 => x"00",
|
||||
1014 => x"ff",
|
||||
1015 => x"4f",
|
||||
1016 => x"4e",
|
||||
1017 => x"4f",
|
||||
1018 => x"00",
|
||||
1019 => x"00",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
@@ -2367,7 +2401,7 @@ architecture arch of DualPortBootBRAM is
|
||||
280 => x"04",
|
||||
281 => x"04",
|
||||
282 => x"9f",
|
||||
283 => x"dc",
|
||||
283 => x"a0",
|
||||
284 => x"80",
|
||||
285 => x"05",
|
||||
286 => x"eb",
|
||||
@@ -2537,7 +2571,7 @@ architecture arch of DualPortBootBRAM is
|
||||
450 => x"08",
|
||||
451 => x"2e",
|
||||
452 => x"0b",
|
||||
453 => x"a8",
|
||||
453 => x"ec",
|
||||
454 => x"0b",
|
||||
455 => x"88",
|
||||
456 => x"0d",
|
||||
@@ -2607,7 +2641,7 @@ architecture arch of DualPortBootBRAM is
|
||||
520 => x"85",
|
||||
521 => x"f9",
|
||||
522 => x"0b",
|
||||
523 => x"ac",
|
||||
523 => x"f0",
|
||||
524 => x"81",
|
||||
525 => x"ed",
|
||||
526 => x"17",
|
||||
@@ -2957,7 +2991,7 @@ architecture arch of DualPortBootBRAM is
|
||||
870 => x"0c",
|
||||
871 => x"81",
|
||||
872 => x"0b",
|
||||
873 => x"ac",
|
||||
873 => x"f0",
|
||||
874 => x"75",
|
||||
875 => x"3d",
|
||||
876 => x"3d",
|
||||
@@ -2992,7 +3026,7 @@ architecture arch of DualPortBootBRAM is
|
||||
905 => x"0d",
|
||||
906 => x"0d",
|
||||
907 => x"0b",
|
||||
908 => x"ac",
|
||||
908 => x"f0",
|
||||
909 => x"5c",
|
||||
910 => x"0c",
|
||||
911 => x"80",
|
||||
@@ -3051,42 +3085,59 @@ architecture arch of DualPortBootBRAM is
|
||||
964 => x"57",
|
||||
965 => x"8c",
|
||||
966 => x"fb",
|
||||
967 => x"90",
|
||||
968 => x"87",
|
||||
969 => x"0c",
|
||||
970 => x"e4",
|
||||
971 => x"94",
|
||||
972 => x"80",
|
||||
973 => x"c0",
|
||||
974 => x"8c",
|
||||
975 => x"87",
|
||||
976 => x"0c",
|
||||
977 => x"f9",
|
||||
978 => x"08",
|
||||
979 => x"98",
|
||||
980 => x"3f",
|
||||
981 => x"38",
|
||||
982 => x"88",
|
||||
983 => x"98",
|
||||
984 => x"87",
|
||||
985 => x"53",
|
||||
986 => x"74",
|
||||
987 => x"3f",
|
||||
988 => x"38",
|
||||
967 => x"c0",
|
||||
968 => x"54",
|
||||
969 => x"52",
|
||||
970 => x"d7",
|
||||
971 => x"90",
|
||||
972 => x"94",
|
||||
973 => x"54",
|
||||
974 => x"52",
|
||||
975 => x"c3",
|
||||
976 => x"08",
|
||||
977 => x"94",
|
||||
978 => x"c0",
|
||||
979 => x"54",
|
||||
980 => x"52",
|
||||
981 => x"ab",
|
||||
982 => x"90",
|
||||
983 => x"94",
|
||||
984 => x"54",
|
||||
985 => x"52",
|
||||
986 => x"97",
|
||||
987 => x"08",
|
||||
988 => x"94",
|
||||
989 => x"80",
|
||||
990 => x"73",
|
||||
991 => x"39",
|
||||
992 => x"73",
|
||||
993 => x"fb",
|
||||
994 => x"ff",
|
||||
995 => x"00",
|
||||
996 => x"ff",
|
||||
997 => x"ff",
|
||||
998 => x"4f",
|
||||
999 => x"49",
|
||||
1000 => x"52",
|
||||
1001 => x"00",
|
||||
1002 => x"00",
|
||||
990 => x"c0",
|
||||
991 => x"8c",
|
||||
992 => x"87",
|
||||
993 => x"0c",
|
||||
994 => x"f9",
|
||||
995 => x"08",
|
||||
996 => x"dc",
|
||||
997 => x"3f",
|
||||
998 => x"38",
|
||||
999 => x"88",
|
||||
1000 => x"98",
|
||||
1001 => x"87",
|
||||
1002 => x"53",
|
||||
1003 => x"74",
|
||||
1004 => x"3f",
|
||||
1005 => x"38",
|
||||
1006 => x"80",
|
||||
1007 => x"73",
|
||||
1008 => x"39",
|
||||
1009 => x"73",
|
||||
1010 => x"fb",
|
||||
1011 => x"ff",
|
||||
1012 => x"00",
|
||||
1013 => x"ff",
|
||||
1014 => x"ff",
|
||||
1015 => x"4f",
|
||||
1016 => x"49",
|
||||
1017 => x"52",
|
||||
1018 => x"00",
|
||||
1019 => x"00",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
@@ -3254,7 +3305,7 @@ architecture arch of DualPortBootBRAM is
|
||||
159 => x"00",
|
||||
160 => x"71",
|
||||
161 => x"0b",
|
||||
162 => x"88",
|
||||
162 => x"cc",
|
||||
163 => x"10",
|
||||
164 => x"06",
|
||||
165 => x"88",
|
||||
@@ -3375,7 +3426,7 @@ architecture arch of DualPortBootBRAM is
|
||||
280 => x"80",
|
||||
281 => x"e2",
|
||||
282 => x"00",
|
||||
283 => x"9f",
|
||||
283 => x"a0",
|
||||
284 => x"38",
|
||||
285 => x"84",
|
||||
286 => x"88",
|
||||
@@ -3661,7 +3712,7 @@ architecture arch of DualPortBootBRAM is
|
||||
566 => x"04",
|
||||
567 => x"75",
|
||||
568 => x"0b",
|
||||
569 => x"ac",
|
||||
569 => x"f0",
|
||||
570 => x"51",
|
||||
571 => x"83",
|
||||
572 => x"06",
|
||||
@@ -3870,7 +3921,7 @@ architecture arch of DualPortBootBRAM is
|
||||
775 => x"04",
|
||||
776 => x"65",
|
||||
777 => x"0b",
|
||||
778 => x"ac",
|
||||
778 => x"f0",
|
||||
779 => x"3f",
|
||||
780 => x"06",
|
||||
781 => x"74",
|
||||
@@ -4059,42 +4110,59 @@ architecture arch of DualPortBootBRAM is
|
||||
964 => x"80",
|
||||
965 => x"0c",
|
||||
966 => x"04",
|
||||
967 => x"9b",
|
||||
968 => x"0b",
|
||||
969 => x"8c",
|
||||
970 => x"86",
|
||||
971 => x"c0",
|
||||
972 => x"8c",
|
||||
973 => x"87",
|
||||
974 => x"0c",
|
||||
975 => x"0b",
|
||||
976 => x"94",
|
||||
977 => x"51",
|
||||
978 => x"88",
|
||||
979 => x"9f",
|
||||
980 => x"df",
|
||||
981 => x"ae",
|
||||
982 => x"0b",
|
||||
967 => x"87",
|
||||
968 => x"08",
|
||||
969 => x"80",
|
||||
970 => x"ea",
|
||||
971 => x"08",
|
||||
972 => x"c0",
|
||||
973 => x"56",
|
||||
974 => x"80",
|
||||
975 => x"ea",
|
||||
976 => x"88",
|
||||
977 => x"c0",
|
||||
978 => x"87",
|
||||
979 => x"08",
|
||||
980 => x"80",
|
||||
981 => x"ea",
|
||||
982 => x"08",
|
||||
983 => x"c0",
|
||||
984 => x"55",
|
||||
985 => x"05",
|
||||
986 => x"52",
|
||||
987 => x"ba",
|
||||
988 => x"8d",
|
||||
989 => x"73",
|
||||
990 => x"38",
|
||||
991 => x"e4",
|
||||
992 => x"54",
|
||||
993 => x"54",
|
||||
994 => x"00",
|
||||
995 => x"ff",
|
||||
996 => x"ff",
|
||||
997 => x"ff",
|
||||
998 => x"42",
|
||||
999 => x"54",
|
||||
1000 => x"2e",
|
||||
1001 => x"00",
|
||||
1002 => x"01",
|
||||
984 => x"56",
|
||||
985 => x"80",
|
||||
986 => x"ea",
|
||||
987 => x"88",
|
||||
988 => x"c0",
|
||||
989 => x"8c",
|
||||
990 => x"87",
|
||||
991 => x"0c",
|
||||
992 => x"0b",
|
||||
993 => x"94",
|
||||
994 => x"51",
|
||||
995 => x"88",
|
||||
996 => x"9f",
|
||||
997 => x"9b",
|
||||
998 => x"ae",
|
||||
999 => x"0b",
|
||||
1000 => x"c0",
|
||||
1001 => x"55",
|
||||
1002 => x"05",
|
||||
1003 => x"52",
|
||||
1004 => x"f6",
|
||||
1005 => x"8d",
|
||||
1006 => x"73",
|
||||
1007 => x"38",
|
||||
1008 => x"e4",
|
||||
1009 => x"54",
|
||||
1010 => x"54",
|
||||
1011 => x"00",
|
||||
1012 => x"ff",
|
||||
1013 => x"ff",
|
||||
1014 => x"ff",
|
||||
1015 => x"42",
|
||||
1016 => x"54",
|
||||
1017 => x"2e",
|
||||
1018 => x"00",
|
||||
1019 => x"01",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
|
||||
@@ -517,7 +517,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
451 => x"38",
|
||||
452 => x"0b",
|
||||
453 => x"0b",
|
||||
454 => x"a8",
|
||||
454 => x"ec",
|
||||
455 => x"83",
|
||||
456 => x"fa",
|
||||
457 => x"7b",
|
||||
@@ -619,7 +619,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
553 => x"0c",
|
||||
554 => x"04",
|
||||
555 => x"0b",
|
||||
556 => x"ac",
|
||||
556 => x"f0",
|
||||
557 => x"88",
|
||||
558 => x"05",
|
||||
559 => x"80",
|
||||
@@ -667,7 +667,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
601 => x"86",
|
||||
602 => x"fa",
|
||||
603 => x"0b",
|
||||
604 => x"ac",
|
||||
604 => x"f0",
|
||||
605 => x"81",
|
||||
606 => x"ff",
|
||||
607 => x"54",
|
||||
@@ -940,7 +940,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
874 => x"0c",
|
||||
875 => x"04",
|
||||
876 => x"0b",
|
||||
877 => x"ac",
|
||||
877 => x"f0",
|
||||
878 => x"54",
|
||||
879 => x"80",
|
||||
880 => x"0b",
|
||||
@@ -1030,42 +1030,59 @@ architecture arch of SinglePortBootBRAM is
|
||||
964 => x"88",
|
||||
965 => x"0d",
|
||||
966 => x"0d",
|
||||
967 => x"e4",
|
||||
968 => x"94",
|
||||
969 => x"90",
|
||||
970 => x"87",
|
||||
971 => x"0c",
|
||||
972 => x"0b",
|
||||
967 => x"8c",
|
||||
968 => x"84",
|
||||
969 => x"51",
|
||||
970 => x"88",
|
||||
971 => x"87",
|
||||
972 => x"08",
|
||||
973 => x"84",
|
||||
974 => x"83",
|
||||
975 => x"94",
|
||||
976 => x"b0",
|
||||
977 => x"3f",
|
||||
978 => x"38",
|
||||
979 => x"fc",
|
||||
980 => x"08",
|
||||
981 => x"80",
|
||||
974 => x"51",
|
||||
975 => x"73",
|
||||
976 => x"87",
|
||||
977 => x"0c",
|
||||
978 => x"9c",
|
||||
979 => x"84",
|
||||
980 => x"51",
|
||||
981 => x"88",
|
||||
982 => x"87",
|
||||
983 => x"0c",
|
||||
984 => x"fc",
|
||||
985 => x"80",
|
||||
986 => x"fd",
|
||||
987 => x"08",
|
||||
988 => x"54",
|
||||
989 => x"86",
|
||||
990 => x"55",
|
||||
991 => x"80",
|
||||
992 => x"80",
|
||||
993 => x"00",
|
||||
994 => x"ff",
|
||||
995 => x"ff",
|
||||
996 => x"ff",
|
||||
997 => x"00",
|
||||
998 => x"54",
|
||||
999 => x"59",
|
||||
1000 => x"4d",
|
||||
1001 => x"00",
|
||||
1002 => x"00",
|
||||
983 => x"08",
|
||||
984 => x"84",
|
||||
985 => x"51",
|
||||
986 => x"73",
|
||||
987 => x"87",
|
||||
988 => x"0c",
|
||||
989 => x"0b",
|
||||
990 => x"84",
|
||||
991 => x"83",
|
||||
992 => x"94",
|
||||
993 => x"f4",
|
||||
994 => x"3f",
|
||||
995 => x"38",
|
||||
996 => x"fc",
|
||||
997 => x"08",
|
||||
998 => x"80",
|
||||
999 => x"87",
|
||||
1000 => x"0c",
|
||||
1001 => x"fc",
|
||||
1002 => x"80",
|
||||
1003 => x"fc",
|
||||
1004 => x"08",
|
||||
1005 => x"54",
|
||||
1006 => x"86",
|
||||
1007 => x"55",
|
||||
1008 => x"80",
|
||||
1009 => x"80",
|
||||
1010 => x"00",
|
||||
1011 => x"ff",
|
||||
1012 => x"ff",
|
||||
1013 => x"ff",
|
||||
1014 => x"00",
|
||||
1015 => x"54",
|
||||
1016 => x"59",
|
||||
1017 => x"4d",
|
||||
1018 => x"00",
|
||||
1019 => x"00",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
@@ -1353,7 +1370,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
279 => x"51",
|
||||
280 => x"00",
|
||||
281 => x"00",
|
||||
282 => x"ac",
|
||||
282 => x"f0",
|
||||
283 => x"27",
|
||||
284 => x"71",
|
||||
285 => x"53",
|
||||
@@ -1531,7 +1548,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
457 => x"78",
|
||||
458 => x"58",
|
||||
459 => x"0b",
|
||||
460 => x"a8",
|
||||
460 => x"ec",
|
||||
461 => x"52",
|
||||
462 => x"70",
|
||||
463 => x"81",
|
||||
@@ -1653,7 +1670,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
579 => x"85",
|
||||
580 => x"fc",
|
||||
581 => x"0b",
|
||||
582 => x"ac",
|
||||
582 => x"f0",
|
||||
583 => x"80",
|
||||
584 => x"15",
|
||||
585 => x"81",
|
||||
@@ -2038,42 +2055,59 @@ architecture arch of SinglePortBootBRAM is
|
||||
964 => x"76",
|
||||
965 => x"3d",
|
||||
966 => x"3d",
|
||||
967 => x"86",
|
||||
968 => x"c0",
|
||||
969 => x"9b",
|
||||
970 => x"0b",
|
||||
971 => x"9c",
|
||||
972 => x"83",
|
||||
973 => x"94",
|
||||
974 => x"80",
|
||||
975 => x"c0",
|
||||
976 => x"9f",
|
||||
977 => x"d6",
|
||||
978 => x"b8",
|
||||
979 => x"51",
|
||||
980 => x"88",
|
||||
981 => x"a0",
|
||||
982 => x"08",
|
||||
983 => x"88",
|
||||
984 => x"3d",
|
||||
985 => x"84",
|
||||
986 => x"51",
|
||||
987 => x"88",
|
||||
988 => x"75",
|
||||
989 => x"2e",
|
||||
990 => x"15",
|
||||
991 => x"a0",
|
||||
992 => x"04",
|
||||
993 => x"39",
|
||||
994 => x"ff",
|
||||
995 => x"ff",
|
||||
996 => x"00",
|
||||
997 => x"ff",
|
||||
998 => x"4f",
|
||||
999 => x"4e",
|
||||
1000 => x"4f",
|
||||
1001 => x"00",
|
||||
1002 => x"00",
|
||||
967 => x"94",
|
||||
968 => x"87",
|
||||
969 => x"73",
|
||||
970 => x"3f",
|
||||
971 => x"2b",
|
||||
972 => x"8c",
|
||||
973 => x"87",
|
||||
974 => x"74",
|
||||
975 => x"3f",
|
||||
976 => x"07",
|
||||
977 => x"8c",
|
||||
978 => x"94",
|
||||
979 => x"87",
|
||||
980 => x"73",
|
||||
981 => x"3f",
|
||||
982 => x"2b",
|
||||
983 => x"9c",
|
||||
984 => x"87",
|
||||
985 => x"74",
|
||||
986 => x"3f",
|
||||
987 => x"07",
|
||||
988 => x"9c",
|
||||
989 => x"83",
|
||||
990 => x"94",
|
||||
991 => x"80",
|
||||
992 => x"c0",
|
||||
993 => x"9f",
|
||||
994 => x"92",
|
||||
995 => x"b8",
|
||||
996 => x"51",
|
||||
997 => x"88",
|
||||
998 => x"a0",
|
||||
999 => x"08",
|
||||
1000 => x"88",
|
||||
1001 => x"3d",
|
||||
1002 => x"84",
|
||||
1003 => x"51",
|
||||
1004 => x"88",
|
||||
1005 => x"75",
|
||||
1006 => x"2e",
|
||||
1007 => x"15",
|
||||
1008 => x"a0",
|
||||
1009 => x"04",
|
||||
1010 => x"39",
|
||||
1011 => x"ff",
|
||||
1012 => x"ff",
|
||||
1013 => x"00",
|
||||
1014 => x"ff",
|
||||
1015 => x"4f",
|
||||
1016 => x"4e",
|
||||
1017 => x"4f",
|
||||
1018 => x"00",
|
||||
1019 => x"00",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
@@ -2362,7 +2396,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
280 => x"04",
|
||||
281 => x"04",
|
||||
282 => x"9f",
|
||||
283 => x"dc",
|
||||
283 => x"a0",
|
||||
284 => x"80",
|
||||
285 => x"05",
|
||||
286 => x"eb",
|
||||
@@ -2532,7 +2566,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
450 => x"08",
|
||||
451 => x"2e",
|
||||
452 => x"0b",
|
||||
453 => x"a8",
|
||||
453 => x"ec",
|
||||
454 => x"0b",
|
||||
455 => x"88",
|
||||
456 => x"0d",
|
||||
@@ -2602,7 +2636,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
520 => x"85",
|
||||
521 => x"f9",
|
||||
522 => x"0b",
|
||||
523 => x"ac",
|
||||
523 => x"f0",
|
||||
524 => x"81",
|
||||
525 => x"ed",
|
||||
526 => x"17",
|
||||
@@ -2952,7 +2986,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
870 => x"0c",
|
||||
871 => x"81",
|
||||
872 => x"0b",
|
||||
873 => x"ac",
|
||||
873 => x"f0",
|
||||
874 => x"75",
|
||||
875 => x"3d",
|
||||
876 => x"3d",
|
||||
@@ -2987,7 +3021,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
905 => x"0d",
|
||||
906 => x"0d",
|
||||
907 => x"0b",
|
||||
908 => x"ac",
|
||||
908 => x"f0",
|
||||
909 => x"5c",
|
||||
910 => x"0c",
|
||||
911 => x"80",
|
||||
@@ -3046,42 +3080,59 @@ architecture arch of SinglePortBootBRAM is
|
||||
964 => x"57",
|
||||
965 => x"8c",
|
||||
966 => x"fb",
|
||||
967 => x"90",
|
||||
968 => x"87",
|
||||
969 => x"0c",
|
||||
970 => x"e4",
|
||||
971 => x"94",
|
||||
972 => x"80",
|
||||
973 => x"c0",
|
||||
974 => x"8c",
|
||||
975 => x"87",
|
||||
976 => x"0c",
|
||||
977 => x"f9",
|
||||
978 => x"08",
|
||||
979 => x"98",
|
||||
980 => x"3f",
|
||||
981 => x"38",
|
||||
982 => x"88",
|
||||
983 => x"98",
|
||||
984 => x"87",
|
||||
985 => x"53",
|
||||
986 => x"74",
|
||||
987 => x"3f",
|
||||
988 => x"38",
|
||||
967 => x"c0",
|
||||
968 => x"54",
|
||||
969 => x"52",
|
||||
970 => x"d7",
|
||||
971 => x"90",
|
||||
972 => x"94",
|
||||
973 => x"54",
|
||||
974 => x"52",
|
||||
975 => x"c3",
|
||||
976 => x"08",
|
||||
977 => x"94",
|
||||
978 => x"c0",
|
||||
979 => x"54",
|
||||
980 => x"52",
|
||||
981 => x"ab",
|
||||
982 => x"90",
|
||||
983 => x"94",
|
||||
984 => x"54",
|
||||
985 => x"52",
|
||||
986 => x"97",
|
||||
987 => x"08",
|
||||
988 => x"94",
|
||||
989 => x"80",
|
||||
990 => x"73",
|
||||
991 => x"39",
|
||||
992 => x"73",
|
||||
993 => x"fb",
|
||||
994 => x"ff",
|
||||
995 => x"00",
|
||||
996 => x"ff",
|
||||
997 => x"ff",
|
||||
998 => x"4f",
|
||||
999 => x"49",
|
||||
1000 => x"52",
|
||||
1001 => x"00",
|
||||
1002 => x"00",
|
||||
990 => x"c0",
|
||||
991 => x"8c",
|
||||
992 => x"87",
|
||||
993 => x"0c",
|
||||
994 => x"f9",
|
||||
995 => x"08",
|
||||
996 => x"dc",
|
||||
997 => x"3f",
|
||||
998 => x"38",
|
||||
999 => x"88",
|
||||
1000 => x"98",
|
||||
1001 => x"87",
|
||||
1002 => x"53",
|
||||
1003 => x"74",
|
||||
1004 => x"3f",
|
||||
1005 => x"38",
|
||||
1006 => x"80",
|
||||
1007 => x"73",
|
||||
1008 => x"39",
|
||||
1009 => x"73",
|
||||
1010 => x"fb",
|
||||
1011 => x"ff",
|
||||
1012 => x"00",
|
||||
1013 => x"ff",
|
||||
1014 => x"ff",
|
||||
1015 => x"4f",
|
||||
1016 => x"49",
|
||||
1017 => x"52",
|
||||
1018 => x"00",
|
||||
1019 => x"00",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
@@ -3249,7 +3300,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
159 => x"00",
|
||||
160 => x"71",
|
||||
161 => x"0b",
|
||||
162 => x"88",
|
||||
162 => x"cc",
|
||||
163 => x"10",
|
||||
164 => x"06",
|
||||
165 => x"88",
|
||||
@@ -3370,7 +3421,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
280 => x"80",
|
||||
281 => x"e2",
|
||||
282 => x"00",
|
||||
283 => x"9f",
|
||||
283 => x"a0",
|
||||
284 => x"38",
|
||||
285 => x"84",
|
||||
286 => x"88",
|
||||
@@ -3656,7 +3707,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
566 => x"04",
|
||||
567 => x"75",
|
||||
568 => x"0b",
|
||||
569 => x"ac",
|
||||
569 => x"f0",
|
||||
570 => x"51",
|
||||
571 => x"83",
|
||||
572 => x"06",
|
||||
@@ -3865,7 +3916,7 @@ architecture arch of SinglePortBootBRAM is
|
||||
775 => x"04",
|
||||
776 => x"65",
|
||||
777 => x"0b",
|
||||
778 => x"ac",
|
||||
778 => x"f0",
|
||||
779 => x"3f",
|
||||
780 => x"06",
|
||||
781 => x"74",
|
||||
@@ -4054,42 +4105,59 @@ architecture arch of SinglePortBootBRAM is
|
||||
964 => x"80",
|
||||
965 => x"0c",
|
||||
966 => x"04",
|
||||
967 => x"9b",
|
||||
968 => x"0b",
|
||||
969 => x"8c",
|
||||
970 => x"86",
|
||||
971 => x"c0",
|
||||
972 => x"8c",
|
||||
973 => x"87",
|
||||
974 => x"0c",
|
||||
975 => x"0b",
|
||||
976 => x"94",
|
||||
977 => x"51",
|
||||
978 => x"88",
|
||||
979 => x"9f",
|
||||
980 => x"df",
|
||||
981 => x"ae",
|
||||
982 => x"0b",
|
||||
967 => x"87",
|
||||
968 => x"08",
|
||||
969 => x"80",
|
||||
970 => x"ea",
|
||||
971 => x"08",
|
||||
972 => x"c0",
|
||||
973 => x"56",
|
||||
974 => x"80",
|
||||
975 => x"ea",
|
||||
976 => x"88",
|
||||
977 => x"c0",
|
||||
978 => x"87",
|
||||
979 => x"08",
|
||||
980 => x"80",
|
||||
981 => x"ea",
|
||||
982 => x"08",
|
||||
983 => x"c0",
|
||||
984 => x"55",
|
||||
985 => x"05",
|
||||
986 => x"52",
|
||||
987 => x"ba",
|
||||
988 => x"8d",
|
||||
989 => x"73",
|
||||
990 => x"38",
|
||||
991 => x"e4",
|
||||
992 => x"54",
|
||||
993 => x"54",
|
||||
994 => x"00",
|
||||
995 => x"ff",
|
||||
996 => x"ff",
|
||||
997 => x"ff",
|
||||
998 => x"42",
|
||||
999 => x"54",
|
||||
1000 => x"2e",
|
||||
1001 => x"00",
|
||||
1002 => x"01",
|
||||
984 => x"56",
|
||||
985 => x"80",
|
||||
986 => x"ea",
|
||||
987 => x"88",
|
||||
988 => x"c0",
|
||||
989 => x"8c",
|
||||
990 => x"87",
|
||||
991 => x"0c",
|
||||
992 => x"0b",
|
||||
993 => x"94",
|
||||
994 => x"51",
|
||||
995 => x"88",
|
||||
996 => x"9f",
|
||||
997 => x"9b",
|
||||
998 => x"ae",
|
||||
999 => x"0b",
|
||||
1000 => x"c0",
|
||||
1001 => x"55",
|
||||
1002 => x"05",
|
||||
1003 => x"52",
|
||||
1004 => x"f6",
|
||||
1005 => x"8d",
|
||||
1006 => x"73",
|
||||
1007 => x"38",
|
||||
1008 => x"e4",
|
||||
1009 => x"54",
|
||||
1010 => x"54",
|
||||
1011 => x"00",
|
||||
1012 => x"ff",
|
||||
1013 => x"ff",
|
||||
1014 => x"ff",
|
||||
1015 => x"42",
|
||||
1016 => x"54",
|
||||
1017 => x"2e",
|
||||
1018 => x"00",
|
||||
1019 => x"01",
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
-- Byte Addressed 32bit BRAM module for the ZPU Evo implementation.
|
||||
--
|
||||
-- Copyright 2018-2019 - Philip Smart for the ZPU Evo implementation.
|
||||
--
|
||||
-- The FreeBSD license
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions
|
||||
-- are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer.
|
||||
-- 2. Redistributions in binary form must reproduce the above
|
||||
-- copyright notice, this list of conditions and the following
|
||||
-- disclaimer in the documentation and/or other materials
|
||||
-- provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED BY THE ZPU PROJECT ``AS IS'' AND ANY
|
||||
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
-- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- ZPU PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
-- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
-- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
-- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
--
|
||||
-- The views and conclusions contained in the software and documentation
|
||||
-- are those of the authors and should not be interpreted as representing
|
||||
-- official policies, either expressed or implied, of the ZPU Project.
|
||||
|
||||
library ieee;
|
||||
library pkgs;
|
||||
library work;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use work.zpu_pkg.all;
|
||||
use work.zpu_soc_pkg.all;
|
||||
|
||||
entity SinglePortBRAM is
|
||||
generic
|
||||
(
|
||||
addrbits : integer := 16
|
||||
);
|
||||
port
|
||||
(
|
||||
clk : in std_logic;
|
||||
memAAddr : in std_logic_vector(addrbits-1 downto 0);
|
||||
memAWriteEnable : in std_logic;
|
||||
memAWriteByte : in std_logic;
|
||||
memAWriteHalfWord : in std_logic;
|
||||
memAWrite : in std_logic_vector(WORD_32BIT_RANGE);
|
||||
memARead : out std_logic_vector(WORD_32BIT_RANGE)
|
||||
);
|
||||
end SinglePortBRAM;
|
||||
|
||||
architecture arch of SinglePortBRAM is
|
||||
|
||||
type ramArray is array(natural range 0 to (2**(addrbits-2))-1) of std_logic_vector(7 downto 0);
|
||||
|
||||
shared variable RAM0 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable RAM1 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable RAM2 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable RAM3 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
signal RAM0_DATA : std_logic_vector(7 downto 0); -- Buffer for byte in word to be written.
|
||||
signal RAM1_DATA : std_logic_vector(7 downto 0); -- Buffer for byte in word to be written.
|
||||
signal RAM2_DATA : std_logic_vector(7 downto 0); -- Buffer for byte in word to be written.
|
||||
signal RAM3_DATA : std_logic_vector(7 downto 0); -- Buffer for byte in word to be written.
|
||||
signal RAM0_WREN : std_logic; -- Write Enable for this particular byte in word.
|
||||
signal RAM1_WREN : std_logic; -- Write Enable for this particular byte in word.
|
||||
signal RAM2_WREN : std_logic; -- Write Enable for this particular byte in word.
|
||||
signal RAM3_WREN : std_logic; -- Write Enable for this particular byte in word.
|
||||
|
||||
begin
|
||||
|
||||
RAM0_DATA <= memAWrite(7 downto 0);
|
||||
RAM0_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "00") or (memAWriteHalfWord = '1' and memAAddr(1) = '0'))
|
||||
else '0';
|
||||
RAM1_DATA <= memAWrite(15 downto 8) when (memAWriteByte = '0' and memAWriteHalfWord = '0') or memAWriteHalfWord = '1'
|
||||
else
|
||||
memAWrite(7 downto 0);
|
||||
RAM1_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "01") or (memAWriteHalfWord = '1' and memAAddr(1) = '0'))
|
||||
else '0';
|
||||
RAM2_DATA <= memAWrite(23 downto 16) when (memAWriteByte = '0' and memAWriteHalfWord = '0')
|
||||
else
|
||||
memAWrite(7 downto 0);
|
||||
RAM2_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "10") or (memAWriteHalfWord = '1' and memAAddr(1) = '1'))
|
||||
else '0';
|
||||
RAM3_DATA <= memAWrite(31 downto 24) when (memAWriteByte = '0' and memAWriteHalfWord = '0')
|
||||
else
|
||||
memAWrite(15 downto 8) when memAWriteHalfWord = '1'
|
||||
else
|
||||
memAWrite(7 downto 0);
|
||||
RAM3_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "11") or (memAWriteHalfWord = '1' and memAAddr(1) = '1'))
|
||||
else '0';
|
||||
|
||||
-- RAM Byte 0 - Port A - bits 7 to 0
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if RAM0_WREN = '1' then
|
||||
RAM0(to_integer(unsigned(memAAddr(addrbits-1 downto 2)))) := RAM0_DATA;
|
||||
else
|
||||
memARead(7 downto 0) <= RAM0(to_integer(unsigned(memAAddr(addrbits-1 downto 2))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- RAM Byte 1 - Port A - bits 15 to 8
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if RAM1_WREN = '1' then
|
||||
RAM1(to_integer(unsigned(memAAddr(addrbits-1 downto 2)))) := RAM1_DATA;
|
||||
else
|
||||
memARead(15 downto 8) <= RAM1(to_integer(unsigned(memAAddr(addrbits-1 downto 2))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- RAM Byte 2 - Port A - bits 23 to 16
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if RAM2_WREN = '1' then
|
||||
RAM2(to_integer(unsigned(memAAddr(addrbits-1 downto 2)))) := RAM2_DATA;
|
||||
else
|
||||
memARead(23 downto 16) <= RAM2(to_integer(unsigned(memAAddr(addrbits-1 downto 2))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- RAM Byte 3 - Port A - bits 31 to 24
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if RAM3_WREN = '1' then
|
||||
RAM3(to_integer(unsigned(memAAddr(addrbits-1 downto 2)))) := RAM3_DATA;
|
||||
else
|
||||
memARead(31 downto 24) <= RAM3(to_integer(unsigned(memAAddr(addrbits-1 downto 2))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end arch;
|
||||
1
devices/sysbus/BRAM/SinglePortBRAM.vhd
Symbolic link
@@ -0,0 +1 @@
|
||||
SinglePortBRAM.vhd.uninitialized
|
||||
@@ -25957,24 +25957,25 @@ architecture arch of SinglePortBRAM is
|
||||
begin
|
||||
|
||||
RAM0_DATA <= memAWrite(7 downto 0);
|
||||
RAM0_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "00") or (memAWriteHalfWord = '1' and memAAddr(1) = '0'))
|
||||
else '0';
|
||||
RAM1_DATA <= memAWrite(15 downto 8) when (memAWriteByte = '0' and memAWriteHalfWord = '0') or memAWriteHalfWord = '1'
|
||||
else
|
||||
memAWrite(7 downto 0);
|
||||
RAM1_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "01") or (memAWriteHalfWord = '1' and memAAddr(1) = '0'))
|
||||
else '0';
|
||||
RAM2_DATA <= memAWrite(23 downto 16) when (memAWriteByte = '0' and memAWriteHalfWord = '0')
|
||||
else
|
||||
memAWrite(7 downto 0);
|
||||
RAM2_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "10") or (memAWriteHalfWord = '1' and memAAddr(1) = '1'))
|
||||
else '0';
|
||||
RAM3_DATA <= memAWrite(31 downto 24) when (memAWriteByte = '0' and memAWriteHalfWord = '0')
|
||||
else
|
||||
memAWrite(15 downto 8) when memAWriteHalfWord = '1'
|
||||
else
|
||||
memAWrite(7 downto 0);
|
||||
RAM3_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "11") or (memAWriteHalfWord = '1' and memAAddr(1) = '1'))
|
||||
|
||||
RAM0_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "11") or (memAWriteHalfWord = '1' and memAAddr(1) = '1'))
|
||||
else '0';
|
||||
RAM1_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "10") or (memAWriteHalfWord = '1' and memAAddr(1) = '1'))
|
||||
else '0';
|
||||
RAM2_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "01") or (memAWriteHalfWord = '1' and memAAddr(1) = '0'))
|
||||
else '0';
|
||||
RAM3_WREN <= '1' when memAWriteEnable = '1' and ((memAWriteByte = '0' and memAWriteHalfWord = '0') or (memAWriteByte = '1' and memAAddr(1 downto 0) = "00") or (memAWriteHalfWord = '1' and memAAddr(1) = '0'))
|
||||
else '0';
|
||||
|
||||
-- RAM Byte 0 - Port A - bits 7 to 0
|
||||
|
||||
@@ -11,10 +11,10 @@ begin
|
||||
end if;
|
||||
|
||||
if (memAWriteEnable = '1') then
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE)))) := memAWrite;
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE)))) := memAWrite;
|
||||
memARead <= memAWrite;
|
||||
else
|
||||
memARead <= ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE))));
|
||||
memARead <= ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
@@ -23,10 +23,10 @@ process (clk)
|
||||
begin
|
||||
if (clk'event and clk = '1') then
|
||||
if (memBWriteEnable = '1') then
|
||||
ram(to_integer(unsigned(memBAddr(ADDR_BIT_BRAM_32BIT_RANGE)))) := memBWrite;
|
||||
ram(to_integer(unsigned(memBAddr(ADDR_32BIT_BRAM_RANGE)))) := memBWrite;
|
||||
memBRead <= memBWrite;
|
||||
else
|
||||
memBRead <= ram(to_integer(unsigned(memBAddr(ADDR_BIT_BRAM_32BIT_RANGE))));
|
||||
memBRead <= ram(to_integer(unsigned(memBAddr(ADDR_32BIT_BRAM_RANGE))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
@@ -14,15 +14,15 @@ begin
|
||||
--
|
||||
if (memAWriteEnable = '1') then
|
||||
if (memAWriteByte = '1') then
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE))))(((wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 0))))*8+7) downto (wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 0))))*8) := memAWrite(7 downto 0);
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE))))(((wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 0))))*8+7) downto (wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 0))))*8) := memAWrite(7 downto 0);
|
||||
elsif (memAWriteWord = '1') then
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE))))(((wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 1))))*16+15) downto (wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 1))))*16) := memAWrite(15 downto 0);
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE))))(((wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 1))))*16+15) downto (wordBytes-1-to_integer(unsigned(memAAddr(byteBits-1 downto 1))))*16) := memAWrite(15 downto 0);
|
||||
else
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE)))) := memAWrite;
|
||||
ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE)))) := memAWrite;
|
||||
end if;
|
||||
memARead <= memAWrite;
|
||||
else
|
||||
memARead <= ram(to_integer(unsigned(memAAddr(ADDR_BIT_BRAM_32BIT_RANGE))));
|
||||
memARead <= ram(to_integer(unsigned(memAAddr(ADDR_32BIT_BRAM_RANGE))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
@@ -31,10 +31,10 @@ process (clk)
|
||||
begin
|
||||
if (clk'event and clk = '1') then
|
||||
if (memBWriteEnable = '1') then
|
||||
ram(to_integer(unsigned(memBAddr(ADDR_BIT_BRAM_32BIT_RANGE)))) := memBWrite;
|
||||
ram(to_integer(unsigned(memBAddr(ADDR_32BIT_BRAM_RANGE)))) := memBWrite;
|
||||
memBRead <= memBWrite;
|
||||
else
|
||||
memBRead <= ram(to_integer(unsigned(memBAddr(ADDR_BIT_BRAM_32BIT_RANGE))));
|
||||
memBRead <= ram(to_integer(unsigned(memBAddr(ADDR_32BIT_BRAM_RANGE))));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
@@ -46,10 +46,10 @@ port (
|
||||
clk : in std_logic;
|
||||
areset : in std_logic := '0';
|
||||
memAWriteEnable : in std_logic;
|
||||
memAAddr : in std_logic_vector(ADDR_BIT_BRAM_32BIT_RANGE);
|
||||
memAAddr : in std_logic_vector(ADDR_32BIT_BRAM_RANGE);
|
||||
memAWrite : in std_logic_vector(WORD_32BIT_RANGE);
|
||||
memBWriteEnable : in std_logic;
|
||||
memBAddr : in std_logic_vector(ADDR_BIT_BRAM_32BIT_RANGE);
|
||||
memBAddr : in std_logic_vector(ADDR_32BIT_BRAM_RANGE);
|
||||
memBWrite : in std_logic_vector(WORD_32BIT_RANGE);
|
||||
memARead : out std_logic_vector(WORD_32BIT_RANGE);
|
||||
memBRead : out std_logic_vector(WORD_32BIT_RANGE)
|
||||
|
||||
@@ -48,12 +48,12 @@ port (
|
||||
memAWriteEnable : in std_logic;
|
||||
memAWriteByte : in std_logic;
|
||||
memAWriteWord : in std_logic;
|
||||
memAAddr : in std_logic_vector(ADDR_BIT_BRAM_32BIT_RANGE);
|
||||
memAAddr : in std_logic_vector(ADDR_32BIT_BRAM_RANGE);
|
||||
memAWrite : in std_logic_vector(WORD_32BIT_RANGE);
|
||||
memARead : out std_logic_vector(WORD_32BIT_RANGE);
|
||||
|
||||
memBWriteEnable : in std_logic;
|
||||
memBAddr : in std_logic_vector(ADDR_BIT_BRAM_32BIT_RANGE);
|
||||
memBAddr : in std_logic_vector(ADDR_32BIT_BRAM_RANGE);
|
||||
memBWrite : in std_logic_vector(WORD_32BIT_RANGE);
|
||||
memBRead : out std_logic_vector(WORD_32BIT_RANGE)
|
||||
);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) wbsdram.vhd ]
|
||||
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) wbsdram.sdc ]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) sdram.vhd ]
|
||||
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) 48LC16M16.sdc ]
|
||||
91
devices/sysbus/SDRAM/48LC16M16.sdc
Normal file
@@ -0,0 +1,91 @@
|
||||
derive_pll_clocks
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Constraints definition original author:
|
||||
# 8/19/2014 D. W. Hawkings (dwh@ovro.caltech.edu)
|
||||
# Adapted and enhanced for the Micron 48LC16M16 SDRAM by Philip Smart Dec 2019.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Clock
|
||||
# Set these variables to the system and memory clock PLL paths for
|
||||
# your board.
|
||||
# -----------------------------------------------------------------
|
||||
set sysclk_pll "mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk"
|
||||
set memclk_pll "mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|divclk"
|
||||
create_generated_clock -name SDRAM_CLK -source $memclk_pll [get_ports {SDRAM_CLK}]
|
||||
derive_clock_uncertainty
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Constraints
|
||||
# -----------------------------------------------------------------
|
||||
#
|
||||
# SDRAM timing parameters
|
||||
#
|
||||
# Generally, the command/address/data all have the same setup/hold
|
||||
# time.
|
||||
#
|
||||
# SDRAM clock can lead System clock by min:
|
||||
# tlead = tcoutmin(FPGA) – th(SDRAM)
|
||||
#
|
||||
# SDRAM clock can lag System clock by min:
|
||||
# tlag = toh(SDRAM) – th(FPGA)
|
||||
#
|
||||
# tSU = Data Setup time (ie. tDS, tAS) on falling edge.
|
||||
# tH = Hold time (ie. tDH, tAH) for SDRAM.
|
||||
# tCOUT (min) = Data out hold time (ie. tOH)
|
||||
# tCOUT (max) = Access time for CL in use (ie. tAC3).
|
||||
#
|
||||
set sdram_tsu 1.5
|
||||
set sdram_th 0.8
|
||||
set sdram_tco_min 3.0
|
||||
set sdram_tco_max 5.4
|
||||
|
||||
# FPGA timing constraints
|
||||
set sdram_input_delay_min $sdram_tco_min
|
||||
set sdram_input_delay_max $sdram_tco_max
|
||||
set sdram_output_delay_min -$sdram_th
|
||||
set sdram_output_delay_max $sdram_tsu
|
||||
|
||||
# PLL to FPGA output (clear the unconstrained path warning)
|
||||
#set_min_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 1
|
||||
#set_max_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 6
|
||||
|
||||
# FPGA Outputs
|
||||
set sdram_outputs [get_ports {
|
||||
SDRAM_CKE
|
||||
SDRAM_CS
|
||||
SDRAM_RAS
|
||||
SDRAM_CAS
|
||||
SDRAM_WE
|
||||
SDRAM_DQM[*]
|
||||
SDRAM_BA[*]
|
||||
SDRAM_ADDR[*]
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_output_delay -clock SDRAM_CLK -min $sdram_output_delay_min $sdram_outputs
|
||||
set_output_delay -clock SDRAM_CLK -max $sdram_output_delay_max $sdram_outputs
|
||||
|
||||
# FPGA Inputs
|
||||
set sdram_inputs [get_ports {
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_input_delay -clock SDRAM_CLK -min $sdram_input_delay_min $sdram_inputs
|
||||
set_input_delay -clock SDRAM_CLK -max $sdram_input_delay_max $sdram_inputs
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM-to-FPGA multi-cycle constraint
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# The PLL is configured so that SDRAM clock leads the system
|
||||
# clock by ~90-degrees (0.25 period or 2.5ns for 100MHz clock).
|
||||
# This will need changing for different clocks, in the PLL
|
||||
# RTL file and the SoC contraints file.
|
||||
|
||||
# The following multi-cycle constraint declares to TimeQuest that
|
||||
# the path between the SDRAM_CLK and the System Clock can be an
|
||||
# extra clock period to the read path to ensure that the latch
|
||||
# clock that occurs 1.25 periods after the launch clock is used in
|
||||
# the timing analysis.
|
||||
#
|
||||
set_multicycle_path -setup -end -from SDRAM_CLK -to $sysclk_pll 2
|
||||
2
devices/sysbus/SDRAM/48LC16M16_cached.qip
Normal file
@@ -0,0 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) sdram_cached.vhd ]
|
||||
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) 48LC16M16.sdc ]
|
||||
@@ -1,2 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) sdram.vhd ]
|
||||
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) sdram.sdc ]
|
||||
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) W9864G6.sdc ]
|
||||
91
devices/sysbus/SDRAM/W9864G6.sdc
Normal file
@@ -0,0 +1,91 @@
|
||||
derive_pll_clocks
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Constraints definition original author:
|
||||
# 8/19/2014 D. W. Hawkings (dwh@ovro.caltech.edu)
|
||||
# Adapted and enhanced for the Winbond W9864G6 SDRAM by Philip Smart Dec 2019.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Clock
|
||||
# Set these variables to the system and memory clock PLL paths for
|
||||
# your board.
|
||||
# -----------------------------------------------------------------
|
||||
set sysclk_pll "mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk"
|
||||
set memclk_pll "mypll|altpll_component|auto_generated|generic_pll2~PLL_OUTPUT_COUNTER|divclk"
|
||||
create_generated_clock -name SDRAM_CLK -source $memclk_pll [get_ports {SDRAM_CLK}]
|
||||
derive_clock_uncertainty
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM Constraints
|
||||
# -----------------------------------------------------------------
|
||||
#
|
||||
# SDRAM timing parameters
|
||||
#
|
||||
# Generally, the command/address/data all have the same setup/hold
|
||||
# time.
|
||||
#
|
||||
# SDRAM clock can lead System clock by min:
|
||||
# tlead = tcoutmin(FPGA) – th(SDRAM)
|
||||
#
|
||||
# SDRAM clock can lag System clock by min:
|
||||
# tlag = toh(SDRAM) – th(FPGA)
|
||||
#
|
||||
# tSU = Data Setup time (ie. tDS, tAS) on falling edge.
|
||||
# tH = Hold time (ie. tDH, tAH) for SDRAM.
|
||||
# tCOUT (min) = Data out hold time (ie. tOH)
|
||||
# tCOUT (max) = Access time for CL in use (ie. tAC3).
|
||||
#
|
||||
set sdram_tsu 1.5
|
||||
set sdram_th 0.8
|
||||
set sdram_tco_min 3.0
|
||||
set sdram_tco_max 5.0
|
||||
|
||||
# FPGA timing constraints
|
||||
set sdram_input_delay_min $sdram_tco_min
|
||||
set sdram_input_delay_max $sdram_tco_max
|
||||
set sdram_output_delay_min -$sdram_th
|
||||
set sdram_output_delay_max $sdram_tsu
|
||||
|
||||
# PLL to FPGA output (clear the unconstrained path warning)
|
||||
#set_min_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 1
|
||||
#set_max_delay -from $memclk_pll -to [get_ports {SDRAM_CLK}] 6
|
||||
|
||||
# FPGA Outputs
|
||||
set sdram_outputs [get_ports {
|
||||
SDRAM_CKE
|
||||
SDRAM_CS
|
||||
SDRAM_RAS
|
||||
SDRAM_CAS
|
||||
SDRAM_WE
|
||||
SDRAM_DQM[*]
|
||||
SDRAM_BA[*]
|
||||
SDRAM_ADDR[*]
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_output_delay -clock SDRAM_CLK -min $sdram_output_delay_min $sdram_outputs
|
||||
set_output_delay -clock SDRAM_CLK -max $sdram_output_delay_max $sdram_outputs
|
||||
|
||||
# FPGA Inputs
|
||||
set sdram_inputs [get_ports {
|
||||
SDRAM_DQ[*]
|
||||
}]
|
||||
set_input_delay -clock SDRAM_CLK -min $sdram_input_delay_min $sdram_inputs
|
||||
set_input_delay -clock SDRAM_CLK -max $sdram_input_delay_max $sdram_inputs
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# SDRAM-to-FPGA multi-cycle constraint
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# The PLL is configured so that SDRAM clock leads the system
|
||||
# clock by ~90-degrees (0.25 period or 2.5ns for 100MHz clock).
|
||||
# This will need changing for different clocks, in the PLL
|
||||
# RTL file and the SoC contraints file.
|
||||
|
||||
# The following multi-cycle constraint declares to TimeQuest that
|
||||
# the path between the SDRAM_CLK and the System Clock can be an
|
||||
# extra clock period to the read path to ensure that the latch
|
||||
# clock that occurs 1.25 periods after the launch clock is used in
|
||||
# the timing analysis.
|
||||
#
|
||||
set_multicycle_path -setup -end -from SDRAM_CLK -to $sysclk_pll 2
|
||||
2
devices/sysbus/SDRAM/W9864G6_cached.qip
Normal file
@@ -0,0 +1,2 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) sdram_cached.vhd ]
|
||||
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) W9864G6.sdc ]
|
||||
@@ -1,50 +0,0 @@
|
||||
library ieee;
|
||||
library pkgs;
|
||||
library work;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use work.zpu_soc_pkg.all;
|
||||
use work.zpu_pkg.all;
|
||||
|
||||
LIBRARY altera_mf;
|
||||
USE altera_mf.altera_mf_components.all;
|
||||
|
||||
entity oddrff is
|
||||
port (
|
||||
CLK: in std_ulogic;
|
||||
D0: in std_logic;
|
||||
D1: in std_logic;
|
||||
O: out std_ulogic
|
||||
);
|
||||
|
||||
end entity oddrff;
|
||||
|
||||
architecture behave of oddrff is
|
||||
signal D0_v, D1_v, O_v: std_logic_vector(0 downto 0);
|
||||
|
||||
|
||||
begin
|
||||
|
||||
ALTDDIO_OUT_component : ALTDDIO_OUT
|
||||
GENERIC MAP (
|
||||
extend_oe_disable => "OFF",
|
||||
intended_device_family => "Cyclone IV E",
|
||||
invert_output => "OFF",
|
||||
lpm_hint => "UNUSED",
|
||||
lpm_type => "altddio_out",
|
||||
oe_reg => "UNREGISTERED",
|
||||
power_up_high => "OFF",
|
||||
width => 1
|
||||
)
|
||||
PORT MAP (
|
||||
datain_h => D1_v,
|
||||
datain_l => D0_v,
|
||||
outclock => CLK,
|
||||
dataout => O_v
|
||||
);
|
||||
|
||||
D1_v(0) <= D0;
|
||||
D0_v(0) <= D1;
|
||||
O <= O_v(0);
|
||||
|
||||
end behave;
|
||||
@@ -1,26 +0,0 @@
|
||||
derive_pll_clocks
|
||||
|
||||
#create_generated_clock -source [get_pins -compatibility_mode {*|pll|pll_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk}]
|
||||
#{*mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk}] \
|
||||
|
||||
#create_generated_clock -source [get_pins -compatibility_mode {mypll|altpll_component|pll|clk[1]}] \
|
||||
# -name MEMCLK [get_ports {MEMCLK}]
|
||||
#create_generated_clock -source [get_pins -compatibility_mode {mypll|altpll_component|pll|clk[1]}] -multiply_by 1 \
|
||||
# -name MEMCLK [get_ports {MEMCLK}]
|
||||
#create_generated_clock -name {MEMCLK} -source [get_ports {CLOCK_12M}] -duty_cycle 50.000 -multiply_by 25 -divide_by 2 -master_clock {clk_12} [get_nets {mypll|altpll_component|_clk1}]
|
||||
#create_generated_clock -name {MEMCLK} -source [get_pins -compatibility_mode {mypll|altpll_component|pll|clk[1]}] -master_clock {MEMCLK} [get_ports {MEMCLK}]
|
||||
|
||||
derive_clock_uncertainty
|
||||
|
||||
# Set acceptable delays for SDRAM chip (See correspondent chip datasheet)
|
||||
set_input_delay -max -clock MEMCLK 6.4ns [get_ports SDRAM_DQ[*]]
|
||||
set_input_delay -min -clock MEMCLK 3.7ns [get_ports SDRAM_DQ[*]]
|
||||
|
||||
# -to [get_clocks {*|pll|pll_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk}]
|
||||
#set_multicycle_path -from [get_clocks {MEMCLK}] \
|
||||
# -to [get_clocks {SYSCLK}] \
|
||||
# -setup 2
|
||||
|
||||
|
||||
set_output_delay -max -clock MEMCLK 1.6ns [get_ports {SDRAM_D* SDRAM_ADDR* SDRAM_BA* SDRAM_CS SDRAM_WE SDRAM_RAS SDRAM_CAS SDRAM_CKE}]
|
||||
set_output_delay -min -clock MEMCLK -0.9ns [get_ports {SDRAM_D* SDRAM_ADDR* SDRAM_BA* SDRAM_CS SDRAM_WE SDRAM_RAS SDRAM_CAS SDRAM_CKE}]
|
||||
@@ -1,19 +0,0 @@
|
||||
derive_pll_clocks
|
||||
|
||||
#create_generated_clock -source [get_pins -compatibility_mode {*|pll|pll_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk}]
|
||||
create_generated_clock -source [get_pins -compatibility_mode {*mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk}] \
|
||||
-name SDRAM_CLK [get_ports {SDRAM_CLK}]
|
||||
|
||||
derive_clock_uncertainty
|
||||
|
||||
# Set acceptable delays for SDRAM chip (See correspondent chip datasheet)
|
||||
set_input_delay -max -clock SDRAM_CLK 6.4ns [get_ports SDRAM_DQ[*]]
|
||||
set_input_delay -min -clock SDRAM_CLK 3.7ns [get_ports SDRAM_DQ[*]]
|
||||
|
||||
# -to [get_clocks {*|pll|pll_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk}]
|
||||
#set_multicycle_path -from [get_clocks {SDRAM_CLK}] \
|
||||
# -to [get_clocks {*mypll|altpll_component|auto_generated|generic_pll1~PLL_OUTPUT_COUNTER|divclk}] \
|
||||
# -setup 2
|
||||
|
||||
set_output_delay -max -clock SDRAM_CLK 1.6ns [get_ports {SDRAM_D* SDRAM_ADDR* SDRAM_BA* SDRAM_CS SDRAM_WE SDRAM_RAS SDRAM_CAS SDRAM_CKE}]
|
||||
set_output_delay -min -clock SDRAM_CLK -0.9ns [get_ports {SDRAM_D* SDRAM_ADDR* SDRAM_BA* SDRAM_CS SDRAM_WE SDRAM_RAS SDRAM_CAS SDRAM_CKE}]
|
||||
@@ -2,22 +2,21 @@
|
||||
--
|
||||
-- Name: sdram.vhd
|
||||
-- Created: September 2019
|
||||
-- Original Author: Stephen J. Leary 2013-2014
|
||||
-- VHDL Author: Philip Smart
|
||||
-- Description: Original Wishbone module written by Stephen J. Leary 2013-2014 in Verilog for use
|
||||
-- with the MT48LC16M16 chip.
|
||||
-- It has been translated into VHDL and adapted for the system bus and undergoing
|
||||
-- extensive modifications to work with the ZPU EVO processor, specifically burst
|
||||
-- tuning to enhance L2 Cache Fill performance.
|
||||
-- Credits:
|
||||
-- Copyright: Copyright (c) 2013-2014, Stephen J. Leary, All rights reserved.
|
||||
-- VHDL translation, sysbus adaptation and enhancements (c) 2019 Philip Smart
|
||||
-- <philip.smart@net2net.org>
|
||||
-- Author: Philip Smart
|
||||
-- Description: A configurable cached sdram controller for use with the ZPU EVO Processor and SoC.
|
||||
-- The module is instantiated with the parameters to describe the underlying SDRAM chip
|
||||
-- and in theory should work with most 16/32 bit SDRAM chips if they adhere to the SDRAM
|
||||
-- standard.
|
||||
-- Credits: Stephen J. Leary 2013-2014 - Basic sdram cycle structure of this module was based on
|
||||
-- the verilog MT48LC16M16 chip controller written by Stephen.
|
||||
-- Copyright: (c) 2019-2020 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: September 2019 - Initial module translation to VHDL based on Stephen J. Leary's Verilog
|
||||
-- source code.
|
||||
-- November 2019 - Adapted for the system bus for use when no Wishbone interface is
|
||||
-- instantiated in the ZPU Evo.
|
||||
-- December 2019 - Extensive changes, metability stability, autorefresh to ACTIVE timing
|
||||
-- and parameterisation.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- This source file is free software: you can redistribute it and-or modify
|
||||
@@ -43,81 +42,95 @@ use work.zpu_pkg.all;
|
||||
|
||||
entity SDRAM is
|
||||
generic (
|
||||
MAX_DATACACHE_BITS : integer := 4; -- Maximum size in addr bits of 32bit datacache for burst transactions.
|
||||
SDRAM_COLUMNS : integer := 256; -- Number of Columns in an SDRAM page (ie. 1 row).
|
||||
SDRAM_ROWS : integer := 4096; -- Number of Rows in the SDRAM.
|
||||
SDRAM_BANKS : integer := 4 -- Number of banks in the SDRAM.
|
||||
MAX_DATACACHE_BITS : integer := 4; -- Maximum size in addr bits of 32bit datacache for burst transactions.
|
||||
SDRAM_ROWS : integer := 4096; -- Number of Rows in the SDRAM.
|
||||
SDRAM_COLUMNS : integer := 256; -- Number of Columns in an SDRAM page (ie. 1 row).
|
||||
SDRAM_BANKS : integer := 4; -- Number of banks in the SDRAM.
|
||||
SDRAM_DATAWIDTH : integer := 16; -- Data width of SDRAM chip (16, 32).
|
||||
SDRAM_CLK_FREQ : integer := 100000000; -- Frequency of the SDRAM clock in Hertz.
|
||||
SDRAM_tRCD : integer := 20; -- tRCD - RAS to CAS minimum period (in ns).
|
||||
SDRAM_tRP : integer := 20; -- tRP - Precharge delay, min time for a precharge command to complete (in ns).
|
||||
SDRAM_tRFC : integer := 70; -- tRFC - Auto-refresh minimum time to complete (in ns), ie. 66ns
|
||||
SDRAM_tREF : integer := 64 -- tREF - period of time a complete refresh of all rows is made within (in ms).
|
||||
);
|
||||
port (
|
||||
-- SDRAM Interface
|
||||
SDRAM_CLK : in std_logic; -- sdram is accessed at 100MHz
|
||||
SDRAM_RST : in std_logic; -- reset the sdram controller.
|
||||
SDRAM_CKE : out std_logic; -- clock enable.
|
||||
SDRAM_DQ : inout std_logic_vector(15 downto 0); -- 16 bit bidirectional data bus
|
||||
SDRAM_ADDR : out std_logic_vector(log2ceil(SDRAM_ROWS) - 1 downto 0); -- Multiplexed address bus
|
||||
SDRAM_DQM : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of byte masks dependent on number of banks.
|
||||
SDRAM_BA : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of banks in SDRAM
|
||||
SDRAM_CS_n : out std_logic; -- Single chip select
|
||||
SDRAM_WE_n : out std_logic; -- write enable
|
||||
SDRAM_RAS_n : out std_logic; -- row address select
|
||||
SDRAM_CAS_n : out std_logic; -- columns address select
|
||||
SDRAM_READY : out std_logic; -- sd ready.
|
||||
SDRAM_CLK : in std_logic; -- SDRAM is accessed at given clock, frequency specified in RAM_CLK.
|
||||
SDRAM_RST : in std_logic; -- Reset the sdram controller.
|
||||
SDRAM_CKE : out std_logic; -- Clock enable.
|
||||
SDRAM_DQ : inout std_logic_vector(SDRAM_DATAWIDTH-1 downto 0); -- Bidirectional data bus
|
||||
SDRAM_ADDR : out std_logic_vector(log2ceil(SDRAM_ROWS) - 1 downto 0); -- Multiplexed address bus
|
||||
SDRAM_DQM : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of byte masks dependent on number of banks.
|
||||
SDRAM_BA : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of banks in SDRAM
|
||||
SDRAM_CS_n : out std_logic; -- Single chip select
|
||||
SDRAM_WE_n : out std_logic; -- Write enable
|
||||
SDRAM_RAS_n : out std_logic; -- Row address select
|
||||
SDRAM_CAS_n : out std_logic; -- Columns address select
|
||||
SDRAM_READY : out std_logic; -- SD ready.
|
||||
|
||||
-- CPU Interface
|
||||
CLK : in std_logic; -- System master clock
|
||||
RESET : in std_logic; -- high active sync reset
|
||||
ADDR : in std_logic_vector(21 downto 0);
|
||||
DATA_IN : in std_logic_vector(31 downto 0); -- write data
|
||||
DATA_OUT : out std_logic_vector(31 downto 0); -- read data
|
||||
WRITE_BYTE : in std_logic; -- write a single byte as specified in A1:A0
|
||||
WRITE_HWORD : in std_logic; -- write a 16bit word as specified in A1
|
||||
CS : in std_logic; -- Chip Select.
|
||||
WREN : in std_logic; -- Write enable.
|
||||
RDEN : in std_logic; -- Read enable.
|
||||
BUSY : out std_logic -- Memory is busy, hold CPU.
|
||||
CLK : in std_logic; -- System master clock
|
||||
RESET : in std_logic; -- High active sync reset
|
||||
ADDR : in std_logic_vector(log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS) downto 0);
|
||||
DATA_IN : in std_logic_vector(WORD_32BIT_RANGE); -- Write data
|
||||
DATA_OUT : out std_logic_vector(WORD_32BIT_RANGE); -- Read data
|
||||
WRITE_BYTE : in std_logic; -- Write a single byte as specified in A1:A0
|
||||
WRITE_HWORD : in std_logic; -- Write a 16bit word as specified in A1
|
||||
CS : in std_logic; -- Chip Select.
|
||||
WREN : in std_logic; -- Write enable.
|
||||
RDEN : in std_logic; -- Read enable.
|
||||
BUSY : out std_logic -- Memory is busy, hold CPU.
|
||||
);
|
||||
end SDRAM;
|
||||
|
||||
architecture Structure of SDRAM is
|
||||
|
||||
-- Constants to define the structure of the SDRAM in bits for provisioning of signals.
|
||||
constant SDRAM_ROW_BITS : integer := log2ceil(SDRAM_ROWS);
|
||||
constant SDRAM_COLUMN_BITS: integer := log2ceil(SDRAM_COLUMNS);
|
||||
constant SDRAM_ARRAY_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS);
|
||||
constant SDRAM_BANK_BITS : integer := log2ceil(SDRAM_BANKS);
|
||||
constant SDRAM_ADDR_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS);
|
||||
|
||||
-- Constants for correct operation of the SDRAM, these values are taken from the datasheet of the target device.
|
||||
--
|
||||
constant tRCD : integer := 4; -- tRCD - RAS to CAS minimum period, ie. 20ns -> 2 cycles@100MHz
|
||||
constant tRP : integer := 4; -- tRP - Precharge delay, min time for a precharge command to complete, ie. 15ns -> 2 cycles@100MHz
|
||||
constant tRFC : integer := 70; -- tRFC - Auto-refresh minimum time to complete, ie. 66ns
|
||||
constant tREF : integer := 64; -- tREF - period of time a complete refresh of all rows is made within.
|
||||
constant RAM_CLK : integer := 50000000; -- SDRAM Clock in Hertz
|
||||
constant SDRAM_ROW_BITS : integer := log2ceil(SDRAM_ROWS);
|
||||
constant SDRAM_COLUMN_BITS : integer := log2ceil(SDRAM_COLUMNS);
|
||||
constant SDRAM_ARRAY_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS);
|
||||
constant SDRAM_BANK_BITS : integer := log2ceil(SDRAM_BANKS);
|
||||
constant SDRAM_ADDR_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS * (SDRAM_DATAWIDTH/8));
|
||||
|
||||
-- Command table for a standard SDRAM.
|
||||
--
|
||||
-- Name (Function) CS# RAS# CAS# WE# DQM ADDR DQ
|
||||
-- COMMAND INHIBIT (NOP) H X X X X X X
|
||||
-- NO OPERATION (NOP) L H H H X X X
|
||||
-- ACTIVE (select bank and activate row) L L H H X Bank/row X
|
||||
-- READ (select bank and column, and start READ burst) L H L H L/H Bank/col X
|
||||
-- WRITE (select bank and column, and start WRITE burst) L H L L L/H Bank/col Valid
|
||||
-- BURST TERMINATE L H H L X X Active
|
||||
-- PRECHARGE (Deactivate row in bank or banks) L L H L X Code X
|
||||
-- AUTO REFRESH or SELF REFRESH (enter self refresh mode) L L L H X X X
|
||||
-- LOAD MODE REGISTER L L L L X Op-code X
|
||||
-- Write enable/output enable X X X X L X Active
|
||||
-- Write inhibit/output High-Z X X X X H X High-Z
|
||||
constant CMD_INHIBIT : std_logic_vector(3 downto 0) := "1111";
|
||||
constant CMD_NOP : std_logic_vector(3 downto 0) := "0111";
|
||||
constant CMD_ACTIVE : std_logic_vector(3 downto 0) := "0011";
|
||||
constant CMD_READ : std_logic_vector(3 downto 0) := "0101";
|
||||
constant CMD_WRITE : std_logic_vector(3 downto 0) := "0100";
|
||||
constant CMD_BURST_TERMINATE : std_logic_vector(3 downto 0) := "0110";
|
||||
constant CMD_PRECHARGE : std_logic_vector(3 downto 0) := "0010";
|
||||
constant CMD_AUTO_REFRESH : std_logic_vector(3 downto 0) := "0001";
|
||||
constant CMD_LOAD_MODE : std_logic_vector(3 downto 0) := "0000";
|
||||
-- Name (Function) CKE CS# RAS# CAS# WE# DQM ADDR DQ
|
||||
-- COMMAND INHIBIT (NOP) H H X X X X X X
|
||||
-- NO OPERATION (NOP) H L H H H X X X
|
||||
-- ACTIVE (select bank and activate row) H L L H H X Bank/row X
|
||||
-- READ (select bank and column, and start READ burst) H L H L H L/H Bank/col X
|
||||
-- WRITE (select bank and column, and start WRITE burst) H L H L L L/H Bank/col Valid
|
||||
-- BURST TERMINATE H L H H L X X Active
|
||||
-- PRECHARGE (Deactivate row in bank or banks) H L L H L X Code X
|
||||
-- AUTO REFRESH or SELF REFRESH (enter self refresh mode) H L L L H X X X
|
||||
-- LOAD MODE REGISTER H L L L L X Op-code X
|
||||
-- Write enable/output enable H X X X X L X Active
|
||||
-- Write inhibit/output High-Z H X X X X H X High-Z
|
||||
-- Self Refresh Entry L L L L H X X X
|
||||
-- Self Refresh Exit (Device is idle) H H X X X X X X
|
||||
-- Self Refresh Exit (Device is in Self Refresh state) H L H H X X X X
|
||||
-- Clock suspend mode Entry L X X X X X X X
|
||||
-- Clock suspend mode Exit H X X X X X X X
|
||||
-- Power down mode Entry (Device is idle) L H X X X X X X
|
||||
-- Power down mode Entry (Device is Active) L L H H X X X X
|
||||
-- Power down mode Exit (Any state) H H X X X X X X
|
||||
-- Power down mode Exit (Device is powered down) H L H H X X X X
|
||||
|
||||
constant CMD_INHIBIT : std_logic_vector(4 downto 0) := "11111";
|
||||
constant CMD_NOP : std_logic_vector(4 downto 0) := "10111";
|
||||
constant CMD_ACTIVE : std_logic_vector(4 downto 0) := "10011";
|
||||
constant CMD_READ : std_logic_vector(4 downto 0) := "10101";
|
||||
constant CMD_WRITE : std_logic_vector(4 downto 0) := "10100";
|
||||
constant CMD_BURST_TERMINATE : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_PRECHARGE : std_logic_vector(4 downto 0) := "10010";
|
||||
constant CMD_AUTO_REFRESH : std_logic_vector(4 downto 0) := "10001";
|
||||
constant CMD_LOAD_MODE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_SELF_REFRESH_START : std_logic_vector(4 downto 0) := "00001";
|
||||
constant CMD_SELF_REFRESH_END : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_CLOCK_SUSPEND : std_logic_vector(4 downto 0) := "00000";
|
||||
constant CMD_CLOCK_RESTORE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_POWER_DOWN : std_logic_vector(4 downto 0) := "01000";
|
||||
constant CMD_POWER_RESTORE : std_logic_vector(4 downto 0) := "01100";
|
||||
|
||||
-- Load Mode Register setting for a standard SDRAM.
|
||||
--
|
||||
@@ -129,110 +142,92 @@ architecture Structure of SDRAM is
|
||||
-- 2:0 = Burst Length : When 000 = 1, 001 = 2, 010 = 4, 011 = 8, all others reserved except 111 when BT = 0 sets full page access.
|
||||
-- | A12-A10 | A9 A8-A7 | A6 A5 A4 | A3Â A2 A1 A0 |
|
||||
-- | reserved| wr burst |reserved| CAS Ltncy|addr mode| burst len|
|
||||
constant WRITE_BURST_MODE : std_logic := '1';
|
||||
constant OP_MODE : std_logic_vector(1 downto 0) := "00";
|
||||
constant CAS_LATENCY : std_logic_vector(2 downto 0) := "011";
|
||||
constant BURST_TYPE : std_logic := '0';
|
||||
constant BURST_LENGTH : std_logic_vector(2 downto 0) := "000";
|
||||
constant MODE : std_logic_vector(SDRAM_ROW_BITS-1 downto 0) := std_logic_vector(to_unsigned(to_integer(unsigned("00" & WRITE_BURST_MODE & OP_MODE & CAS_LATENCY & BURST_TYPE & BURST_LENGTH)), SDRAM_ROW_BITS));
|
||||
constant WRITE_BURST_MODE : std_logic := '1';
|
||||
constant OP_MODE : std_logic_vector(1 downto 0) := "00";
|
||||
constant CAS_LATENCY : std_logic_vector(2 downto 0) := "011";
|
||||
constant BURST_TYPE : std_logic := '0';
|
||||
constant BURST_LENGTH : std_logic_vector(2 downto 0) := "000";
|
||||
constant MODE : std_logic_vector(SDRAM_ROW_BITS-1 downto 0) := std_logic_vector(to_unsigned(to_integer(unsigned("00" & WRITE_BURST_MODE & OP_MODE & CAS_LATENCY & BURST_TYPE & BURST_LENGTH)), SDRAM_ROW_BITS));
|
||||
|
||||
-- FSM Cycle States governed in units of time, the state changes location according to the configurable parameters to ensure correct actuation at the correct time.
|
||||
--
|
||||
constant CYCLE_PRECHARGE : integer := 0; -- 0
|
||||
constant CYCLE_RAS_START : integer := tRP; -- 3
|
||||
constant CYCLE_RAS_NEXT : integer := CYCLE_RAS_START + 1; -- 4
|
||||
constant CYCLE_CAS0 : integer := CYCLE_RAS_START + tRCD; -- 3 + tRCD
|
||||
constant CYCLE_CAS1 : integer := CYCLE_CAS0 + 1; -- 4 + tRCD
|
||||
constant CYCLE_READ0 : integer := CYCLE_CAS0 + to_integer(unsigned(CAS_LATENCY)) + 1; -- 3 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_READ1 : integer := CYCLE_READ0 + 1; -- 4 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_END : integer := CYCLE_READ1 + 4; -- 9 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_RFSH_START : integer := CYCLE_RAS_START; -- 3
|
||||
constant CYCLE_RFSH_END : integer := CYCLE_RFSH_START + ((tRFC/RAM_CLK) * 10000000) + 1; -- 3 + tRFC in clock ticks.
|
||||
constant CYCLE_PRECHARGE : integer := 0; -- ~0
|
||||
constant CYCLE_RAS_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~3
|
||||
constant CYCLE_CAS_START : integer := CYCLE_RAS_START + clockTicks(SDRAM_tRCD, SDRAM_CLK_FREQ); -- ~3 + tRCD
|
||||
constant CYCLE_CAS_END : integer := CYCLE_CAS_START + 1; -- ~4 + tRCD
|
||||
constant CYCLE_READ_START : integer := CYCLE_CAS_START + to_integer(unsigned(CAS_LATENCY)) + 1; -- ~3 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_READ_END : integer := CYCLE_READ_START + 1; -- ~4 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_END : integer := CYCLE_READ_END + 1; -- ~9 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_RFSH_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~tRP
|
||||
constant CYCLE_RFSH_END : integer := CYCLE_RFSH_START + clockTicks(SDRAM_tRFC, SDRAM_CLK_FREQ) + clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ) + 1; -- ~tRP (start) + tRFC (min autorefresh time) + tRP (end) in clock ticks.
|
||||
|
||||
-- Period in clock cycles between SDRAM refresh cycles.
|
||||
constant REFRESH_PERIOD : integer := (RAM_CLK / (tREF * SDRAM_ROWS)) - CYCLE_END;
|
||||
-- Period in clock cycles between SDRAM refresh cycles. This equates to tREF / SDRAM_ROWS to evenly divide the time, then subtract the length of the refresh period as this is
|
||||
-- the time it takes when a refresh starts until completion.
|
||||
constant REFRESH_PERIOD : integer := (((SDRAM_tREF * SDRAM_CLK_FREQ ) / SDRAM_ROWS) - (SDRAM_tRFC * 1000)) / 1000;
|
||||
|
||||
type BankArray is array(natural range 0 to 3) of std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
-- Array of row addresses, one per bank, to indicate the row in use per bank.
|
||||
type BankArray is array(natural range 0 to SDRAM_BANKS-1) of std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
|
||||
-- Cache for holding burst reads to allow for differing speeds of WishBone Master.
|
||||
type DataCacheArray is array(natural range 0 to ((2**(MAX_DATACACHE_BITS))-1)) of std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal readCache : DataCacheArray;
|
||||
attribute ramstyle : string;
|
||||
attribute ramstyle of readCache : signal is "logic";
|
||||
signal cacheReadAddr : unsigned(MAX_DATACACHE_BITS-1 downto 0);
|
||||
signal cacheWriteAddr : unsigned(MAX_DATACACHE_BITS-1 downto 0);
|
||||
-- SDRAM domain signals.
|
||||
signal sdBusy : std_logic;
|
||||
signal sdCycle : integer range 0 to 31;
|
||||
signal sdDataOut : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal sdDone : std_logic;
|
||||
shared variable sdCmd : std_logic_vector(4 downto 0);
|
||||
signal sdRefreshCount : unsigned(11 downto 0);
|
||||
signal sdAutoRefresh : std_logic;
|
||||
signal sdResetTimer : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdInResetCounter : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdIsReady : std_logic;
|
||||
signal sdActiveRow : BankArray;
|
||||
signal sdActiveBank : std_logic_vector(1 downto 0);
|
||||
|
||||
signal sbBusy : std_logic;
|
||||
signal sdCycle : integer range 0 to 31;
|
||||
signal sdDone : std_logic;
|
||||
signal sdCmd : std_logic_vector(3 downto 0);
|
||||
signal sdRefreshCount : unsigned(9 downto 0);
|
||||
signal sdAutoRefresh : std_logic;
|
||||
-- CPU domain signals.
|
||||
signal cpuBusy : std_logic;
|
||||
signal cpuDQM : std_logic_vector(3 downto 0);
|
||||
signal cpuDoneLast : std_logic;
|
||||
signal cpuBank : natural range 0 to SDRAM_BANKS-1;
|
||||
signal cpuRow : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
signal cpuCol : std_logic_vector(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
signal cpuDataIn : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal cpuIsWriting : std_logic;
|
||||
signal cpuLastEN : std_logic;
|
||||
|
||||
signal sdResetTimer : unsigned(7 downto 0);
|
||||
signal sdMuxAddr : std_logic_vector(SDRAM_ROW_BITS-1 downto 0); -- 12 bit multiplexed address bus
|
||||
signal sdDoneLast : std_logic;
|
||||
signal sdInResetCounter : unsigned(7 downto 0);
|
||||
signal sdIsWriting : std_logic;
|
||||
signal isReady : std_logic;
|
||||
signal sdDataOut : std_logic_vector(15 downto 0);
|
||||
signal sdDataIn : std_logic_vector(15 downto 0);
|
||||
signal sdActiveRow : BankArray;
|
||||
signal sdActiveBank : std_logic_vector(1 downto 0);
|
||||
signal sdBank : natural range 0 to 3;
|
||||
signal sdRow : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
signal sdCol : std_logic_vector(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
signal sdDQM : std_logic_vector(1 downto 0);
|
||||
signal sdCKE : std_logic;
|
||||
|
||||
signal cpuDQM : std_logic_vector(3 downto 0);
|
||||
|
||||
signal dout : std_logic_vector(31 downto 0);
|
||||
signal cpuDataIn : std_logic_vector(31 downto 0);
|
||||
begin
|
||||
|
||||
-- Tri-state control of the SDRAM data bus.
|
||||
process(sdIsWriting, SDRAM_DQ, sdDataOut)
|
||||
begin
|
||||
if (sdIsWriting = '1') then
|
||||
SDRAM_DQ <= sdDataOut;
|
||||
sdDataIn <= SDRAM_DQ;
|
||||
else
|
||||
SDRAM_DQ <= (others => 'Z');
|
||||
sdDataIn <= SDRAM_DQ;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Main FSM for SDRAM control and refresh.
|
||||
process(SDRAM_CLK, SDRAM_RST)
|
||||
process(ALL)
|
||||
begin
|
||||
|
||||
if (SDRAM_RST = '1') then
|
||||
sdResetTimer <= (others => '0'); -- 0 upto 127
|
||||
sdResetTimer <= (others => '0'); -- 0 upto 255
|
||||
sdInResetCounter <= (others => '1'); -- 255 downto 0
|
||||
sdMuxAddr <= (others => '0');
|
||||
sdAutoRefresh <= '0';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
isReady <= '0';
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCKE <= '1';
|
||||
sdDQM <= (others => '1');
|
||||
sdIsReady <= '0';
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
SDRAM_DQM <= (others => '1');
|
||||
sdCycle <= 0;
|
||||
sdDone <= '0';
|
||||
cacheWriteAddr <= (others => '0');
|
||||
|
||||
elsif rising_edge(SDRAM_CLK) then
|
||||
|
||||
-- Tri-state control of the SDRAM databus, when reading, the output drivers are disabled.
|
||||
if (cpuIsWriting = '0') then
|
||||
SDRAM_DQ <= (others => 'Z');
|
||||
end if;
|
||||
|
||||
-- If no specific command given the default is NOP.
|
||||
sdCmd <= CMD_NOP;
|
||||
sdCmd := CMD_NOP;
|
||||
|
||||
-- Initialisation on power up or reset. The SDRAM must be given at least 200uS to initialise and a fixed setup pattern applied.
|
||||
if (isReady = '0') then
|
||||
if (sdIsReady = '0') then
|
||||
sdResetTimer <= sdResetTimer + 1;
|
||||
|
||||
-- 1uS timer.
|
||||
if (sdResetTimer = RAM_CLK/1000000) then
|
||||
if (sdResetTimer = SDRAM_CLK_FREQ/1000000) then
|
||||
sdResetTimer <= (others => '0');
|
||||
sdInResetCounter <= sdInResetCounter - 1;
|
||||
end if;
|
||||
@@ -245,44 +240,55 @@ begin
|
||||
|
||||
-- Precharge all banks
|
||||
if(sdInResetCounter = 55) then
|
||||
sdCmd <= CMD_PRECHARGE;
|
||||
sdMuxAddr(10) <= '1';
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 40 and sdInResetCounter <= 48) then
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- Load the Mode register with our parameters.
|
||||
if(sdInResetCounter = 39) then
|
||||
sdCmd <= CMD_LOAD_MODE;
|
||||
sdMuxAddr <= MODE;
|
||||
sdCmd := CMD_LOAD_MODE;
|
||||
SDRAM_ADDR <= MODE;
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 30 and sdInResetCounter <= 38) then
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- SDRAM ready.
|
||||
if(sdInResetCounter = 20) then
|
||||
isReady <= '1';
|
||||
sdIsReady <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
else
|
||||
|
||||
-- Counter to time periods between autorefresh.
|
||||
sdRefreshCount <= sdRefreshCount + 1;
|
||||
|
||||
-- Auto refresh. On timeout it kicks in so that 8192 auto refreshes are
|
||||
-- issued in a 64ms period. Other bus operations are stalled during this period.
|
||||
-- This mechanism is used to reduce the possibility of metastability issues due to differing clocks.
|
||||
-- We only act after both Busy signals are high, thus one SDRAM clock after cpuBusy goes high.
|
||||
sdBusy <= cpuBusy;
|
||||
|
||||
-- If the SDRAM has completed its request, reset the done indicator as it is only 1 cycle wide.
|
||||
if sdDone = '1' then
|
||||
sdDone <= '0';
|
||||
end if;
|
||||
|
||||
-- Auto refresh. On timeout it kicks in so that ROWS auto refreshes are
|
||||
-- issued in a tRFC period. Other bus operations are stalled during this period.
|
||||
if (sdRefreshCount > REFRESH_PERIOD and sdCycle = 0) then
|
||||
sdAutoRefresh <= '1';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdCmd <= CMD_PRECHARGE;
|
||||
sdMuxAddr(10) <= '1';
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
|
||||
@@ -293,7 +299,7 @@ begin
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
when CYCLE_RFSH_START =>
|
||||
sdCmd <= CMD_AUTO_REFRESH;
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
|
||||
when CYCLE_RFSH_END =>
|
||||
-- reset the count.
|
||||
@@ -302,143 +308,166 @@ begin
|
||||
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
elsif ((sbBusy = '1' and sdCycle = 0) or sdCycle /= 0) then -- or (sdCycle = 0 and CS = '1')) then
|
||||
|
||||
elsif (((cpuBusy = '1' and sdBusy = '1') and sdCycle = 0) or sdCycle /= 0) then
|
||||
|
||||
-- while the cycle is active count.
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
|
||||
when CYCLE_PRECHARGE =>
|
||||
-- If the bank is not open then no need to precharge, move onto RAS.
|
||||
if (sdActiveBank(sdBank) = '0') then
|
||||
if (sdActiveBank(cpuBank) = '0') then
|
||||
sdCycle <= CYCLE_RAS_START;
|
||||
|
||||
-- If the requested row is already active, go to CAS for immediate access to this row.
|
||||
elsif (sdActiveRow(sdBank) = sdRow) then
|
||||
sdCycle <= CYCLE_CAS0;
|
||||
elsif (sdActiveRow(cpuBank) = cpuRow) then
|
||||
sdCycle <= CYCLE_CAS_START;
|
||||
|
||||
-- Otherwise we close out the open bank by issuing a PRECHARGE.
|
||||
else
|
||||
sdCmd <= CMD_PRECHARGE;
|
||||
sdMuxAddr(10) <= '0';
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length));
|
||||
sdActiveBank(sdBank) <= '0'; -- Store flag to indicate which bank is being made active.
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '0';
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length));
|
||||
sdActiveBank(cpuBank) <= '0'; -- Store flag to indicate which bank is being made active.
|
||||
end if;
|
||||
|
||||
-- Open the requested row.
|
||||
when CYCLE_RAS_START =>
|
||||
sdCmd <= CMD_ACTIVE;
|
||||
sdMuxAddr <= sdRow; -- Addr presented to SDRAM as row address.
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length)); -- Addr presented to SDRAM as bank select.
|
||||
sdActiveRow(sdBank) <= sdRow; -- Store number of row being made active
|
||||
sdActiveBank(sdBank) <= '1'; -- Store flag to indicate which bank is being made active.
|
||||
sdCmd := CMD_ACTIVE;
|
||||
SDRAM_ADDR <= cpuRow; -- Addr presented to SDRAM as row address.
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length)); -- Addr presented to SDRAM as bank select.
|
||||
sdActiveRow(cpuBank) <= cpuRow; -- Store number of row being made active
|
||||
sdActiveBank(cpuBank) <= '1'; -- Store flag to indicate which bank is being made active.
|
||||
|
||||
when CYCLE_RAS_NEXT =>
|
||||
sdDQM <= "11"; -- Set DQ to tri--state.
|
||||
|
||||
-- this is the first CAS cycle
|
||||
when CYCLE_CAS0 =>
|
||||
-- Process on a 32bit boundary, as this is a 16bit chip we need 2 accesses for a 32bit alignment.
|
||||
sdMuxAddr <= std_logic_vector(to_unsigned(to_integer(unsigned(sdCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length)); -- Ensure bank is the correct one opened.
|
||||
|
||||
-- CAS start, for 32 bit chips, only 1 CAS cycle is needed, for 16bit chips we need 2 to read/write 2x16bit words.
|
||||
when CYCLE_CAS_START =>
|
||||
|
||||
-- If writing, setup for a write with preset mask.
|
||||
if (sdIsWriting = '1') then
|
||||
sdCmd <= CMD_WRITE;
|
||||
sdDQM <= not cpuDQM(3 downto 2);
|
||||
sdDataOut <= cpuDataIn(31 downto 16); -- Assign corresponding data to the SDRAM databus.
|
||||
if (cpuIsWriting = '1') then
|
||||
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 2) & '0' & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing 32bit data with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn; -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 0);
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn((SDRAM_DATAWIDTH*2)-1 downto SDRAM_DATAWIDTH); -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 2);
|
||||
else
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
sdCmd := CMD_WRITE;
|
||||
|
||||
else
|
||||
-- Setup for a read.
|
||||
sdCmd <= CMD_READ;
|
||||
sdDQM <= "00"; -- For reads dont mask the data output.
|
||||
sdCmd := CMD_READ;
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_DQM <= "00"; -- For reads dont mask the data output.
|
||||
end if;
|
||||
|
||||
when CYCLE_CAS1 =>
|
||||
sdMuxAddr <= std_logic_vector(to_unsigned(to_integer(unsigned(sdCol(SDRAM_COLUMN_BITS-1 downto 1) & '1')), SDRAM_ROW_BITS)); -- CAS address = Next address accessing second 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(sdBank, SDRAM_BA'length)); -- Ensure bank is the correct one opened.
|
||||
when CYCLE_CAS_END =>
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '1')), SDRAM_ROW_BITS)); -- CAS address = Next address accessing second 16bit location within the 32bit external alignment with no auto precharge
|
||||
|
||||
-- If writing, setup for a write with preset mask.
|
||||
if (sdIsWriting = '1') then
|
||||
sdCmd <= CMD_WRITE;
|
||||
sdDQM <= not cpuDQM(1 downto 0);
|
||||
sdDone <= not sdDone;
|
||||
sdDataOut <= cpuDataIn(15 downto 0);
|
||||
sdCycle <= CYCLE_END;
|
||||
-- When writing, setup for a write with preset mask with the correct word.
|
||||
if (cpuIsWriting = '1') then
|
||||
SDRAM_DQM <= not cpuDQM(1 downto 0);
|
||||
SDRAM_DQ <= cpuDataIn(SDRAM_DATAWIDTH-1 downto 0);
|
||||
sdDone <= '1';
|
||||
sdCycle <= CYCLE_END;
|
||||
sdCmd := CMD_WRITE;
|
||||
else
|
||||
-- Setup for a read, change to write if flag set.
|
||||
sdCmd <= CMD_READ;
|
||||
sdDQM <= "00"; -- For reads dont mask the data output.
|
||||
sdCmd := CMD_READ;
|
||||
SDRAM_DQM <= "00"; -- For reads dont mask the data output.
|
||||
end if;
|
||||
|
||||
-- Data is available CAS Latency clocks after the read request.
|
||||
when CYCLE_READ0 =>
|
||||
-- If writing, then we are complete, exit else read the first word.
|
||||
if (sdIsWriting = '1') then
|
||||
-- Data is available CAS Latency clocks after the read request. For 32bit chips, only 1 cycle is needed, for 16bit we need 2 read cycles of
|
||||
-- 16 bits each.
|
||||
when CYCLE_READ_START =>
|
||||
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
sdDataOut <= SDRAM_DQ;
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
sdDataOut((SDRAM_DATAWIDTH*2)-1 downto SDRAM_DATAWIDTH) <= SDRAM_DQ;
|
||||
else
|
||||
dout(31 downto 16) <= sdDataIn;
|
||||
end if;
|
||||
|
||||
when CYCLE_READ1 =>
|
||||
-- If writing, then we are complete, exit else read the first word.
|
||||
if (sdIsWriting = '1') then
|
||||
sdCycle <= CYCLE_END;
|
||||
else
|
||||
dout(15 downto 0) <= sdDataIn;
|
||||
sdDone <= not sdDone;
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
|
||||
-- Second and final read cycle for 16bit SDRAM chips to create a 32bit word.
|
||||
when CYCLE_READ_END =>
|
||||
sdDataOut(SDRAM_DATAWIDTH-1 downto 0) <= SDRAM_DQ;
|
||||
|
||||
when CYCLE_END =>
|
||||
sdDone <= '1';
|
||||
sdCycle <= 0;
|
||||
|
||||
-- Other states are wait states, waiting for the correct time slot for SDRAM access.
|
||||
when others =>
|
||||
end case;
|
||||
else
|
||||
sdCycle <= 0;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- drive control signals according to current command
|
||||
SDRAM_CKE <= sdCmd(4);
|
||||
SDRAM_CS_n <= sdCmd(3);
|
||||
SDRAM_RAS_n <= sdCmd(2);
|
||||
SDRAM_CAS_n <= sdCmd(1);
|
||||
SDRAM_WE_n <= sdCmd(0);
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
|
||||
-- CPU/BUS side logic. When the CPU initiates a transaction, capture the signals and the captured values are used within the SDRAM domain. This is to prevent
|
||||
-- any changes CPU side or differing signal lengths due to CPU architecture or clock being propogated into the SDRAM domain. The CPU only needs to know
|
||||
-- when the transation is complete and data read.
|
||||
--
|
||||
process(RESET, CLK, CS, WRITE_BYTE, WRITE_HWORD, ADDR, WREN, RDEN, isReady)
|
||||
process(ALL)
|
||||
begin
|
||||
if (RESET = '1') then
|
||||
sdDoneLast <= '0';
|
||||
sbBusy <= '0';
|
||||
sdBank <= 0;
|
||||
sdRow <= (others => '0');
|
||||
sdCol <= (others => '0');
|
||||
cpuDoneLast <= '0';
|
||||
cpuBusy <= '0';
|
||||
cpuBank <= 0;
|
||||
cpuRow <= (others => '0');
|
||||
cpuCol <= (others => '0');
|
||||
cpuDQM <= (others => '1');
|
||||
sdIsWriting <= '0';
|
||||
cpuLastEN <= '0';
|
||||
|
||||
-- If the SDRAM isnt ready, we can only wait.
|
||||
elsif isReady = '0' then
|
||||
-- Wait for the SDRAM to become ready by holding the CPU in a wait state.
|
||||
elsif sdIsReady = '0' then
|
||||
cpuBusy <= '1';
|
||||
|
||||
elsif rising_edge(CLK) then
|
||||
|
||||
-- Preserve current enable state to detect activation.
|
||||
cpuLastEN <= (RDEN or WREN) and CS;
|
||||
|
||||
-- Detect a Chip Select state change signalling access.
|
||||
if CS = '1' and (WREN='1' or RDEN='1') then
|
||||
sbBusy <= '1';
|
||||
sdIsWriting <= WREN;
|
||||
sdBank <= to_integer(unsigned(ADDR(SDRAM_ADDR_BITS-1 downto SDRAM_ARRAY_BITS)));
|
||||
sdRow <= std_logic_vector(to_unsigned(to_integer(unsigned(ADDR(SDRAM_ARRAY_BITS + 1 - SDRAM_BANK_BITS downto SDRAM_COLUMN_BITS))), SDRAM_ROW_BITS));
|
||||
sdCol <= ADDR(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
if cpuLastEN = '0' and (RDEN = '1' or WREN = '1') then
|
||||
cpuBusy <= '1';
|
||||
cpuIsWriting <= WREN;
|
||||
cpuBank <= to_integer(unsigned(ADDR(SDRAM_ADDR_BITS-1 downto SDRAM_ARRAY_BITS+1)));
|
||||
cpuRow <= std_logic_vector(to_unsigned(to_integer(unsigned(ADDR(SDRAM_ARRAY_BITS downto SDRAM_COLUMN_BITS+1))), SDRAM_ROW_BITS));
|
||||
cpuCol <= ADDR(SDRAM_COLUMN_BITS downto 2) & '0';
|
||||
|
||||
-- Preset the write selects according to the CPU signals. Let Quartus optimize as easier to read seeing all mask values.
|
||||
if(WRITE_BYTE = '1') then
|
||||
case ADDR(1 downto 0) is
|
||||
when "00" => cpuDQM <= "1000";
|
||||
cpuDataIn <= DATA_IN(7 downto 0) & X"000000";
|
||||
cpuDataIn <= DATA_IN(WORD_8BIT_RANGE) & X"000000";
|
||||
when "01" => cpuDQM <= "0100";
|
||||
cpuDataIn <= X"00" & DATA_IN(7 downto 0) & X"0000";
|
||||
cpuDataIn <= X"00" & DATA_IN(WORD_8BIT_RANGE) & X"0000";
|
||||
when "10" => cpuDQM <= "0010";
|
||||
cpuDataIn <= X"0000" & DATA_IN(7 downto 0) & X"00";
|
||||
cpuDataIn <= X"0000" & DATA_IN(WORD_8BIT_RANGE) & X"00";
|
||||
when "11" => cpuDQM <= "0001";
|
||||
cpuDataIn <= X"000000" & DATA_IN(7 downto 0);
|
||||
cpuDataIn <= X"000000" & DATA_IN(WORD_8BIT_RANGE);
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
@@ -446,43 +475,35 @@ begin
|
||||
|
||||
case ADDR(1) is
|
||||
when '0' => cpuDQM <= "1100";
|
||||
cpuDataIn <= DATA_IN(15 downto 0) & X"0000";
|
||||
cpuDataIn <= DATA_IN(WORD_16BIT_RANGE) & X"0000";
|
||||
when '1' => cpuDQM <= "0011";
|
||||
cpuDataIn <= X"0000" & DATA_IN(15 downto 0);
|
||||
cpuDataIn <= X"0000" & DATA_IN(WORD_16BIT_RANGE);
|
||||
end case;
|
||||
|
||||
else
|
||||
-- Reads are always 32bit wide and if no part word signal is asserted, writes are 32bit.
|
||||
cpuDataIn <= DATA_IN(31 downto 0);
|
||||
cpuDataIn <= DATA_IN(WORD_32BIT_RANGE);
|
||||
cpuDQM <= "1111";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Note SDRAM activity via a previous/last signal.
|
||||
sdDoneLast <= sdDone;
|
||||
cpuDoneLast <= sdDone;
|
||||
|
||||
-- If there has been a change in the SDRAM activity reset the signals as initiated transaction is complete.
|
||||
if (sdDone xor sdDoneLast) = '1' then
|
||||
sbBusy <= '0';
|
||||
sdIsWriting <= '0';
|
||||
-- A change in the Done signal indicates the end of the SDRAM request so read the data (read request) and release the CPU.
|
||||
if (cpuDoneLast = '0' and sdDone = '1') then
|
||||
DATA_OUT <= sdDataOut;
|
||||
end if;
|
||||
if (cpuDoneLast = '1' and sdDone = '0') then
|
||||
cpuBusy <= '0';
|
||||
cpuIsWriting <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
DATA_OUT <= dout;
|
||||
|
||||
-- drive control signals according to current command
|
||||
SDRAM_CS_n <= sdCmd(3);
|
||||
SDRAM_RAS_n <= sdCmd(2);
|
||||
SDRAM_CAS_n <= sdCmd(1);
|
||||
SDRAM_WE_n <= sdCmd(0);
|
||||
SDRAM_CKE <= sdCKE;
|
||||
SDRAM_DQM <= sdDQM;
|
||||
SDRAM_ADDR <= sdMuxAddr;
|
||||
|
||||
-- System bus control signals.
|
||||
BUSY <= sbBusy;
|
||||
SDRAM_READY <= isReady;
|
||||
BUSY <= '1' when (cpuLastEN = '0' and (RDEN = '1' or WREN = '1')) else cpuBusy;
|
||||
SDRAM_READY <= sdIsReady;
|
||||
|
||||
end Structure;
|
||||
|
||||
736
devices/sysbus/SDRAM/sdram_cached.vhd
Normal file
@@ -0,0 +1,736 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
--
|
||||
-- Name: sdram_cached.vhd
|
||||
-- Created: September 2019
|
||||
-- Author: Philip Smart
|
||||
-- Description: A configurable cached sdram controller for use with the ZPU EVO Processor and SoC.
|
||||
-- The module is instantiated with the parameters to describe the underlying SDRAM chip
|
||||
-- and in theory should work with most 16/32 bit SDRAM chips if they adhere to the SDRAM
|
||||
-- standard.
|
||||
-- Credits: Stephen J. Leary 2013-2014 - Basic sdram cycle structure of this module was based on
|
||||
-- the verilog MT48LC16M16 chip controller written by Stephen.
|
||||
-- Copyright: (c) 2019-2020 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: September 2019 - Initial module translation to VHDL based on Stephen J. Leary's Verilog
|
||||
-- source code.
|
||||
-- November 2019 - Adapted for the system bus for use when no Wishbone interface is
|
||||
-- instantiated in the ZPU Evo.
|
||||
-- December 2019 - Extensive changes, metability stability, autorefresh to ACTIVE timing
|
||||
-- and parameterisation.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- This source file is free software: you can redistribute it and-or modify
|
||||
-- it under the terms of the GNU General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This source file is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http:--www.gnu.org-licenses->.
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
library pkgs;
|
||||
library work;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use work.zpu_soc_pkg.all;
|
||||
use work.zpu_pkg.all;
|
||||
|
||||
entity SDRAM is
|
||||
generic (
|
||||
MAX_DATACACHE_BITS : integer := 4; -- Maximum size in addr bits of 32bit datacache for burst transactions.
|
||||
SDRAM_ROWS : integer := 4096; -- Number of Rows in the SDRAM.
|
||||
SDRAM_COLUMNS : integer := 256; -- Number of Columns in an SDRAM page (ie. 1 row).
|
||||
SDRAM_BANKS : integer := 4; -- Number of banks in the SDRAM.
|
||||
SDRAM_DATAWIDTH : integer := 16; -- Data width of SDRAM chip (16, 32).
|
||||
SDRAM_CLK_FREQ : integer := 100000000; -- Frequency of the SDRAM clock in Hertz.
|
||||
SDRAM_tRCD : integer := 20; -- tRCD - RAS to CAS minimum period (in ns).
|
||||
SDRAM_tRP : integer := 20; -- tRP - Precharge delay, min time for a precharge command to complete (in ns).
|
||||
SDRAM_tRFC : integer := 70; -- tRFC - Auto-refresh minimum time to complete (in ns), ie. 66ns
|
||||
SDRAM_tREF : integer := 64 -- tREF - period of time a complete refresh of all rows is made within (in ms).
|
||||
);
|
||||
port (
|
||||
-- SDRAM Interface
|
||||
SDRAM_CLK : in std_logic; -- SDRAM is accessed at given clock, frequency specified in RAM_CLK.
|
||||
SDRAM_RST : in std_logic; -- Reset the sdram controller.
|
||||
SDRAM_CKE : out std_logic; -- Clock enable.
|
||||
SDRAM_DQ : inout std_logic_vector(SDRAM_DATAWIDTH-1 downto 0); -- Bidirectional data bus
|
||||
SDRAM_ADDR : out std_logic_vector(log2ceil(SDRAM_ROWS) - 1 downto 0); -- Multiplexed address bus
|
||||
SDRAM_DQM : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of byte masks dependent on number of banks.
|
||||
SDRAM_BA : out std_logic_vector(log2ceil(SDRAM_BANKS) - 1 downto 0); -- Number of banks in SDRAM
|
||||
SDRAM_CS_n : out std_logic; -- Single chip select
|
||||
SDRAM_WE_n : out std_logic; -- Write enable
|
||||
SDRAM_RAS_n : out std_logic; -- Row address select
|
||||
SDRAM_CAS_n : out std_logic; -- Columns address select
|
||||
SDRAM_READY : out std_logic; -- SD ready.
|
||||
|
||||
-- CPU Interface
|
||||
CLK : in std_logic; -- System master clock
|
||||
RESET : in std_logic; -- High active sync reset
|
||||
ADDR : in std_logic_vector(log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS) downto 0);
|
||||
DATA_IN : in std_logic_vector(WORD_32BIT_RANGE); -- Write data
|
||||
DATA_OUT : out std_logic_vector(WORD_32BIT_RANGE); -- Read data
|
||||
WRITE_BYTE : in std_logic; -- Write a single byte as specified in A1:A0
|
||||
WRITE_HWORD : in std_logic; -- Write a 16bit word as specified in A1
|
||||
CS : in std_logic; -- Chip Select.
|
||||
WREN : in std_logic; -- Write enable.
|
||||
RDEN : in std_logic; -- Read enable.
|
||||
BUSY : out std_logic -- Memory is busy, hold CPU.
|
||||
);
|
||||
end SDRAM;
|
||||
|
||||
architecture Structure of SDRAM is
|
||||
|
||||
-- Constants to define the structure of the SDRAM in bits for provisioning of signals.
|
||||
constant SDRAM_ROW_BITS : integer := log2ceil(SDRAM_ROWS);
|
||||
constant SDRAM_COLUMN_BITS : integer := log2ceil(SDRAM_COLUMNS);
|
||||
constant SDRAM_ARRAY_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS);
|
||||
constant SDRAM_BANK_BITS : integer := log2ceil(SDRAM_BANKS);
|
||||
constant SDRAM_ADDR_BITS : integer := log2ceil(SDRAM_ROWS * SDRAM_COLUMNS * SDRAM_BANKS * (SDRAM_DATAWIDTH/8));
|
||||
|
||||
-- Command table for a standard SDRAM.
|
||||
--
|
||||
-- Name (Function) CKE CS# RAS# CAS# WE# DQM ADDR DQ
|
||||
-- COMMAND INHIBIT (NOP) H H X X X X X X
|
||||
-- NO OPERATION (NOP) H L H H H X X X
|
||||
-- ACTIVE (select bank and activate row) H L L H H X Bank/row X
|
||||
-- READ (select bank and column, and start READ burst) H L H L H L/H Bank/col X
|
||||
-- WRITE (select bank and column, and start WRITE burst) H L H L L L/H Bank/col Valid
|
||||
-- BURST TERMINATE H L H H L X X Active
|
||||
-- PRECHARGE (Deactivate row in bank or banks) H L L H L X Code X
|
||||
-- AUTO REFRESH or SELF REFRESH (enter self refresh mode) H L L L H X X X
|
||||
-- LOAD MODE REGISTER H L L L L X Op-code X
|
||||
-- Write enable/output enable H X X X X L X Active
|
||||
-- Write inhibit/output High-Z H X X X X H X High-Z
|
||||
-- Self Refresh Entry L L L L H X X X
|
||||
-- Self Refresh Exit (Device is idle) H H X X X X X X
|
||||
-- Self Refresh Exit (Device is in Self Refresh state) H L H H X X X X
|
||||
-- Clock suspend mode Entry L X X X X X X X
|
||||
-- Clock suspend mode Exit H X X X X X X X
|
||||
-- Power down mode Entry (Device is idle) L H X X X X X X
|
||||
-- Power down mode Entry (Device is Active) L L H H X X X X
|
||||
-- Power down mode Exit (Any state) H H X X X X X X
|
||||
-- Power down mode Exit (Device is powered down) H L H H X X X X
|
||||
|
||||
constant CMD_INHIBIT : std_logic_vector(4 downto 0) := "11111";
|
||||
constant CMD_NOP : std_logic_vector(4 downto 0) := "10111";
|
||||
constant CMD_ACTIVE : std_logic_vector(4 downto 0) := "10011";
|
||||
constant CMD_READ : std_logic_vector(4 downto 0) := "10101";
|
||||
constant CMD_WRITE : std_logic_vector(4 downto 0) := "10100";
|
||||
constant CMD_BURST_TERMINATE : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_PRECHARGE : std_logic_vector(4 downto 0) := "10010";
|
||||
constant CMD_AUTO_REFRESH : std_logic_vector(4 downto 0) := "10001";
|
||||
constant CMD_LOAD_MODE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_SELF_REFRESH_START : std_logic_vector(4 downto 0) := "00001";
|
||||
constant CMD_SELF_REFRESH_END : std_logic_vector(4 downto 0) := "10110";
|
||||
constant CMD_CLOCK_SUSPEND : std_logic_vector(4 downto 0) := "00000";
|
||||
constant CMD_CLOCK_RESTORE : std_logic_vector(4 downto 0) := "10000";
|
||||
constant CMD_POWER_DOWN : std_logic_vector(4 downto 0) := "01000";
|
||||
constant CMD_POWER_RESTORE : std_logic_vector(4 downto 0) := "01100";
|
||||
|
||||
-- Load Mode Register setting for a standard SDRAM.
|
||||
--
|
||||
-- xx:10 = Reserved :
|
||||
-- 9 = Write Burst Mode : 0 = Programmed Burst Length, 1 = Single Location Access
|
||||
-- 8:7 = Operating Mode : 00 = Standard Operation, all other values reserved.
|
||||
-- 6:4 = CAS Latency : 010 = 2, 011 = 3, all other values reserved.
|
||||
-- 3 = Burst Type : 0 = Sequential, 1 = Interleaved.
|
||||
-- 2:0 = Burst Length : When 000 = 1, 001 = 2, 010 = 4, 011 = 8, all others reserved except 111 when BT = 0 sets full page access.
|
||||
-- | A12-A10 | A9 A8-A7 | A6 A5 A4 | A3Â A2 A1 A0 |
|
||||
-- | reserved| wr burst |reserved| CAS Ltncy|addr mode| burst len|
|
||||
constant WRITE_BURST_MODE : std_logic := '1';
|
||||
constant OP_MODE : std_logic_vector(1 downto 0) := "00";
|
||||
constant CAS_LATENCY : std_logic_vector(2 downto 0) := "011";
|
||||
constant BURST_TYPE : std_logic := '0';
|
||||
constant BURST_LENGTH : std_logic_vector(2 downto 0) := "111";
|
||||
constant MODE : std_logic_vector(SDRAM_ROW_BITS-1 downto 0) := std_logic_vector(to_unsigned(to_integer(unsigned("00" & WRITE_BURST_MODE & OP_MODE & CAS_LATENCY & BURST_TYPE & BURST_LENGTH)), SDRAM_ROW_BITS));
|
||||
|
||||
-- FSM Cycle States governed in units of time, the state changes location according to the configurable parameters to ensure correct actuation at the correct time.
|
||||
--
|
||||
constant CYCLE_PRECHARGE : integer := 0; -- ~0
|
||||
constant CYCLE_RAS_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~3
|
||||
constant CYCLE_CAS_START : integer := CYCLE_RAS_START + clockTicks(SDRAM_tRCD, SDRAM_CLK_FREQ); -- ~3 + tRCD
|
||||
constant CYCLE_WRITE_END : integer := CYCLE_CAS_START + 1; -- ~4 + tRCD
|
||||
constant CYCLE_READ_START : integer := CYCLE_CAS_START + to_integer(unsigned(CAS_LATENCY)) + 1; -- ~3 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_READ_END : integer := CYCLE_READ_START + 1; -- ~4 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_END : integer := CYCLE_READ_END + 1; -- ~9 + tRCD + CAS_LATENCY
|
||||
constant CYCLE_RFSH_START : integer := clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ); -- ~tRP
|
||||
constant CYCLE_RFSH_END : integer := CYCLE_RFSH_START + clockTicks(SDRAM_tRFC, SDRAM_CLK_FREQ) + clockTicks(SDRAM_tRP, SDRAM_CLK_FREQ) + 1; -- ~tRP (start) + tRFC (min autorefresh time) + tRP (end) in clock ticks.
|
||||
|
||||
-- Period in clock cycles between SDRAM refresh cycles. This equates to tREF / SDRAM_ROWS to evenly divide the time, then subtract the length of the refresh period as this is
|
||||
-- the time it takes when a refresh starts until completion.
|
||||
constant REFRESH_PERIOD : integer := (((SDRAM_tREF * SDRAM_CLK_FREQ ) / SDRAM_ROWS) - (SDRAM_tRFC * 1000)) / 1000;
|
||||
|
||||
-- Array of row addresses, one per bank, to indicate the row in use per bank.
|
||||
type BankArray is array(natural range 0 to SDRAM_BANKS-1) of std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
type BankCacheArray is array(natural range 0 to SDRAM_BANKS-1) of std_logic_vector(((SDRAM_ROW_BITS-1)+SDRAM_BANK_BITS) downto 0);
|
||||
|
||||
-- SDRAM domain signals.
|
||||
signal sdBusy : std_logic;
|
||||
signal sdCycle : integer range 0 to 31;
|
||||
signal sdDone : std_logic;
|
||||
shared variable sdCmd : std_logic_vector(4 downto 0);
|
||||
signal sdRefreshCount : unsigned(11 downto 0);
|
||||
signal sdAutoRefresh : std_logic;
|
||||
signal sdResetTimer : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdInResetCounter : unsigned(WORD_8BIT_RANGE);
|
||||
signal sdIsReady : std_logic;
|
||||
signal sdActiveRow : BankArray;
|
||||
signal sdActiveBank : std_logic_vector(1 downto 0);
|
||||
signal sdWriteColumnAddr : unsigned(SDRAM_COLUMN_BITS-1 downto 0); -- Address at byte level as bit 0 is used as part of the fifo write enable.
|
||||
signal sdWriteCnt : integer range 0 to SDRAM_COLUMNS-1;
|
||||
|
||||
-- CPU domain signals.
|
||||
signal cpuBusy : std_logic;
|
||||
signal cpuDQM : std_logic_vector(3 downto 0);
|
||||
signal cpuBank : natural range 0 to SDRAM_BANKS-1;
|
||||
signal cpuRow : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
signal cpuCol : std_logic_vector(SDRAM_COLUMN_BITS-1 downto 0);
|
||||
signal cpuDataOut : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal cpuDataIn : std_logic_vector(WORD_32BIT_RANGE);
|
||||
signal cpuDoneLast : std_logic;
|
||||
signal cpuIsWriting : std_logic;
|
||||
signal cpuLastEN : std_logic;
|
||||
signal cpuCachedBank : std_logic_vector(SDRAM_BANK_BITS-1 downto 0);
|
||||
signal cpuCachedRow : BankCacheArray;
|
||||
|
||||
-- Infer a BRAM array for 4 banks of 16bit words. 32bit is created by 2 arrays.
|
||||
type ramArray is array(natural range 0 to ((SDRAM_COLUMNS/2)*4)-1) of std_logic_vector(WORD_8BIT_RANGE);
|
||||
|
||||
-- Declare the BRAM arrays for 32bit as a set of 4 x 8bit banks.
|
||||
shared variable fifoCache_3 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable fifoCache_2 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable fifoCache_1 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
shared variable fifoCache_0 : ramArray :=
|
||||
(
|
||||
others => X"00"
|
||||
);
|
||||
|
||||
-- Fifo control signals.
|
||||
signal fifoDataOutHi : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoDataOutLo : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoDataInHi : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoDataInLo : std_logic_vector(WORD_16BIT_RANGE);
|
||||
signal fifoSdWREN_1 : std_logic;
|
||||
signal fifoSdWREN_0 : std_logic;
|
||||
signal fifoCPUWREN_3 : std_logic;
|
||||
signal fifoCPUWREN_2 : std_logic;
|
||||
signal fifoCPUWREN_1 : std_logic;
|
||||
signal fifoCPUWREN_0 : std_logic;
|
||||
begin
|
||||
|
||||
-- Main FSM for SDRAM control and refresh.
|
||||
process(ALL)
|
||||
begin
|
||||
|
||||
if (SDRAM_RST = '1') then
|
||||
sdResetTimer <= (others => '0'); -- 0 upto 127
|
||||
sdInResetCounter <= (others => '1'); -- 255 downto 0
|
||||
sdAutoRefresh <= '0';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
sdIsReady <= '0';
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
SDRAM_DQM <= (others => '1');
|
||||
sdCycle <= 0;
|
||||
sdDone <= '0';
|
||||
fifoSdWREN_0 <= '0';
|
||||
fifoSdWREN_1 <= '0';
|
||||
sdWriteColumnAddr <= (others => '0');
|
||||
|
||||
elsif rising_edge(SDRAM_CLK) then
|
||||
|
||||
-- Write Enables are only 1 clock wide, clear on each cycle.
|
||||
fifoSdWREN_1 <= '0';
|
||||
fifoSdWREN_0 <= '0';
|
||||
|
||||
-- Tri-state control, set the SDRAM databus to tri-state if we are not in write mode.
|
||||
if (cpuIsWriting = '0') then
|
||||
SDRAM_DQ <= (others => 'Z');
|
||||
end if;
|
||||
|
||||
-- If no specific command given the default is NOP.
|
||||
sdCmd := CMD_NOP;
|
||||
|
||||
-- Initialisation on power up or reset. The SDRAM must be given at least 200uS to initialise and a fixed setup pattern applied.
|
||||
if (sdIsReady = '0') then
|
||||
sdResetTimer <= sdResetTimer + 1;
|
||||
|
||||
-- 1uS timer.
|
||||
if (sdResetTimer = SDRAM_CLK_FREQ/1000000) then
|
||||
sdResetTimer <= (others => '0');
|
||||
sdInResetCounter <= sdInResetCounter - 1;
|
||||
end if;
|
||||
|
||||
-- Every 1uS check for the next init action.
|
||||
if (sdResetTimer = 0) then
|
||||
|
||||
-- 200uS wait, no action as the SDRAM starts up.
|
||||
-- ie. 255 downto 55
|
||||
|
||||
-- Precharge all banks
|
||||
if(sdInResetCounter = 55) then
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 40 and sdInResetCounter <= 48) then
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- Load the Mode register with our parameters.
|
||||
if(sdInResetCounter = 39) then
|
||||
sdCmd := CMD_LOAD_MODE;
|
||||
SDRAM_ADDR <= MODE;
|
||||
end if;
|
||||
|
||||
-- 8 auto refresh commands as specified in datasheet. The RFS time is 60nS, so using a 1uS timer, issue one after
|
||||
-- the other.
|
||||
if(sdInResetCounter >= 30 and sdInResetCounter <= 38) then
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
end if;
|
||||
|
||||
-- SDRAM ready.
|
||||
if(sdInResetCounter = 20) then
|
||||
sdIsReady <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
else
|
||||
|
||||
-- Counter to time periods between autorefresh.
|
||||
sdRefreshCount <= sdRefreshCount + 1;
|
||||
|
||||
-- This mechanism is used to reduce the possibility of metastability issues due to differing clocks.
|
||||
-- We only act after both Busy signals are high, thus one SDRAM clock after cpuBusy goes high.
|
||||
sdBusy <= cpuBusy;
|
||||
|
||||
-- Auto refresh. On timeout it kicks in so that ROWS auto refreshes are
|
||||
-- issued in a tRFC period. Other bus operations are stalled during this period.
|
||||
if (sdRefreshCount > REFRESH_PERIOD and sdCycle = 0) then
|
||||
sdAutoRefresh <= '1';
|
||||
sdRefreshCount <= (others => '0');
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '1';
|
||||
sdActiveBank <= (others => '0');
|
||||
sdActiveRow <= ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
|
||||
|
||||
-- In auto refresh period.
|
||||
elsif (sdAutoRefresh = '1') then
|
||||
|
||||
-- while the cycle is active count.
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
when CYCLE_RFSH_START =>
|
||||
sdCmd := CMD_AUTO_REFRESH;
|
||||
|
||||
when CYCLE_RFSH_END =>
|
||||
-- reset the count.
|
||||
sdAutoRefresh <= '0';
|
||||
sdCycle <= 0;
|
||||
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
elsif ((cpuBusy = '1' and sdCycle = 0) or sdCycle /= 0) then -- or (sdCycle = 0 and CS = '1')) then
|
||||
|
||||
-- while the cycle is active count.
|
||||
sdCycle <= sdCycle + 1;
|
||||
case (sdCycle) is
|
||||
|
||||
when CYCLE_PRECHARGE =>
|
||||
-- If the bank is not open then no need to precharge, move onto RAS.
|
||||
if (sdActiveBank(cpuBank) = '0') then
|
||||
sdCycle <= CYCLE_RAS_START;
|
||||
|
||||
-- If the requested row is already active, go to CAS for immediate access to this row.
|
||||
elsif (sdActiveRow(cpuBank) = cpuRow) then
|
||||
sdCycle <= CYCLE_CAS_START;
|
||||
|
||||
-- Otherwise we close out the open bank by issuing a PRECHARGE.
|
||||
else
|
||||
sdCmd := CMD_PRECHARGE;
|
||||
SDRAM_ADDR(10) <= '0';
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length));
|
||||
sdActiveBank(cpuBank) <= '0'; -- Store flag to indicate which bank is being made active.
|
||||
end if;
|
||||
|
||||
-- Open the requested row.
|
||||
when CYCLE_RAS_START =>
|
||||
sdCmd := CMD_ACTIVE;
|
||||
SDRAM_ADDR <= cpuRow; -- Addr presented to SDRAM as row address.
|
||||
SDRAM_BA <= std_logic_vector(to_unsigned(cpuBank, SDRAM_BA'length)); -- Addr presented to SDRAM as bank select.
|
||||
sdActiveRow(cpuBank) <= cpuRow; -- Store number of row being made active
|
||||
sdActiveBank(cpuBank) <= '1'; -- Store flag to indicate which bank is being made active.
|
||||
|
||||
-- CAS start, for 32 bit chips, only 1 CAS cycle is needed, for 16bit chips we need 2 to read/write 2x16bit words.
|
||||
when CYCLE_CAS_START =>
|
||||
-- If writing, setup for a write with preset mask.
|
||||
if (cpuIsWriting = '1') then
|
||||
sdCmd := CMD_WRITE;
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 2) & '0' & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing 32bit data with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn; -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 0);
|
||||
sdDone <= '1';
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
-- A fake statement used to convince Quartus Prime to infer block ram for the fifo and not use registers.
|
||||
fifoDataInHi <= fifoDataOutHi;
|
||||
fifoDataInLo <= fifoDataOutLo;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '0')), SDRAM_ROW_BITS)); -- CAS address = Address accessing first 16bit location within the 32bit external alignment with no auto precharge
|
||||
SDRAM_DQ <= cpuDataIn((SDRAM_DATAWIDTH*2)-1 downto SDRAM_DATAWIDTH); -- Assign corresponding data to the SDRAM databus.
|
||||
SDRAM_DQM <= not cpuDQM(3 downto 2);
|
||||
|
||||
-- A fake statement used to convince Quartus Prime to infer block ram for the fifo and not use registers.
|
||||
fifoDataInHi <= fifoDataOutHi;
|
||||
else
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
|
||||
else
|
||||
-- Setup for a read.
|
||||
sdCmd := CMD_READ;
|
||||
SDRAM_ADDR <= (others => '0');
|
||||
SDRAM_DQM <= "00"; -- For reads dont mask the data output.
|
||||
sdWriteCnt <= SDRAM_COLUMNS-1;
|
||||
sdWriteColumnAddr <= (others => '1');
|
||||
end if;
|
||||
|
||||
-- For writes, this state writes out the second word of a 32bit word if we have a 16bit wide SDRAM chip.
|
||||
--
|
||||
when CYCLE_WRITE_END =>
|
||||
-- When writing, setup for a write with preset mask with the correct word.
|
||||
if (cpuIsWriting = '1') then
|
||||
SDRAM_ADDR <= std_logic_vector(to_unsigned(to_integer(unsigned(cpuCol(SDRAM_COLUMN_BITS-1 downto 1) & '1')), SDRAM_ROW_BITS)); -- CAS address = Next address accessing second 16bit location within the 32bit external alignment with no auto precharge
|
||||
sdCmd := CMD_WRITE;
|
||||
SDRAM_DQM <= not cpuDQM(1 downto 0);
|
||||
SDRAM_DQ <= cpuDataIn(SDRAM_DATAWIDTH-1 downto 0);
|
||||
sdDone <= '1';
|
||||
sdCycle <= CYCLE_END;
|
||||
|
||||
-- A fake statement used to convince Quartus Prime to infer block ram for the fifo and not use registers.
|
||||
fifoDataInLo <= fifoDataOutLo;
|
||||
end if;
|
||||
|
||||
-- Data is available after CAS Latency (2 or 3) clocks after the read request.
|
||||
-- The data is read as a full page burst, 1 clock per word.
|
||||
when CYCLE_READ_START =>
|
||||
|
||||
if SDRAM_DATAWIDTH = 32 then
|
||||
fifoSdWREN_1 <= '1';
|
||||
fifoSdWREN_0 <= '1';
|
||||
sdWriteCnt <= sdWriteCnt - 2;
|
||||
sdWriteColumnAddr <= sdWriteColumnAddr + 2;
|
||||
fifoDataInHi <= SDRAM_DQ(WORD_UPPER_16BIT_RANGE);
|
||||
fifoDataInLo <= SDRAM_DQ(WORD_LOWER_16BIT_RANGE);
|
||||
|
||||
if sdWriteCnt > 1 then
|
||||
sdCycle <= CYCLE_READ_START;
|
||||
end if;
|
||||
|
||||
elsif SDRAM_DATAWIDTH = 16 then
|
||||
if fifoSdWREN_1 = '0' then
|
||||
fifoSdWREN_1 <= '1';
|
||||
fifoDataInHi <= SDRAM_DQ;
|
||||
else
|
||||
fifoSdWREN_0 <= '1';
|
||||
fifoDataInLo <= SDRAM_DQ;
|
||||
end if;
|
||||
sdWriteCnt <= sdWriteCnt - 1;
|
||||
sdWriteColumnAddr <= sdWriteColumnAddr + 1;
|
||||
|
||||
if sdWriteCnt > 0 then
|
||||
sdCycle <= CYCLE_READ_START;
|
||||
end if;
|
||||
|
||||
else
|
||||
report "SDRAM datawidth parameter invalid, should be 16 or 32!" severity error;
|
||||
end if;
|
||||
|
||||
when CYCLE_READ_END =>
|
||||
sdDone <= '1';
|
||||
|
||||
when CYCLE_END =>
|
||||
sdCycle <= 0;
|
||||
sdDone <= '0';
|
||||
|
||||
-- Other states are wait states, waiting for the correct time slot for SDRAM access.
|
||||
when others =>
|
||||
end case;
|
||||
else
|
||||
sdCycle <= 0;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- drive control signals according to current command
|
||||
SDRAM_CKE <= sdCmd(4);
|
||||
SDRAM_CS_n <= sdCmd(3);
|
||||
SDRAM_RAS_n <= sdCmd(2);
|
||||
SDRAM_CAS_n <= sdCmd(1);
|
||||
SDRAM_WE_n <= sdCmd(0);
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- CPU/BUS side logic. When the CPU initiates a transaction, capture the signals and the captured values are used within the SDRAM domain. This is to prevent
|
||||
-- any changes CPU side or differing signal lengths due to CPU architecture or clock being propogated into the SDRAM domain. The CPU only needs to know
|
||||
-- when the transation is complete and data read.
|
||||
--
|
||||
process(ALL)
|
||||
variable bank : std_logic_vector(1 downto 0);
|
||||
variable row : std_logic_vector(SDRAM_ROW_BITS-1 downto 0);
|
||||
variable writeThru : std_logic;
|
||||
begin
|
||||
|
||||
-- Setup the bank and row as variables to make code reading easier.
|
||||
bank := ADDR(SDRAM_ADDR_BITS-1) & ADDR((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1));
|
||||
row := ADDR(SDRAM_ADDR_BITS-2 downto (SDRAM_COLUMN_BITS+SDRAM_BANK_BITS));
|
||||
|
||||
-- For write operations, if the cached page row for the current bank is the same as the row given by the cpu then we write to both the SDRAM and to the cache.
|
||||
if cpuCachedBank(to_integer(unsigned(bank))) = '1' and cpuCachedRow(to_integer(unsigned(bank))) = ADDR(SDRAM_ADDR_BITS-1) & ADDR((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1)) & row then
|
||||
writeThru := '1';
|
||||
else
|
||||
writeThru := '0';
|
||||
end if;
|
||||
|
||||
-- Setup signals to initial state, critical they start at the right values.
|
||||
if (RESET = '1') then
|
||||
cpuDoneLast <= '0';
|
||||
cpuBusy <= '0';
|
||||
cpuBank <= 0;
|
||||
cpuRow <= (others => '0');
|
||||
cpuCol <= (others => '0');
|
||||
cpuDQM <= (others => '1');
|
||||
cpuLastEN <= '0';
|
||||
cpuCachedBank <= (others => '0');
|
||||
cpuCachedRow <= ( others => (others => '0') );
|
||||
fifoCPUWREN_3 <= '0';
|
||||
fifoCPUWREN_2 <= '0';
|
||||
fifoCPUWREN_1 <= '0';
|
||||
fifoCPUWREN_0 <= '0';
|
||||
|
||||
-- Wait for the SDRAM to become ready by holding the CPU in a wait state.
|
||||
elsif sdIsReady = '0' then
|
||||
cpuBusy <= '1';
|
||||
|
||||
elsif rising_edge(CLK) then
|
||||
|
||||
-- CPU Cache writes are only 1 cycle wide, so clear any asserted write.
|
||||
fifoCPUWREN_3 <= '0';
|
||||
fifoCPUWREN_2 <= '0';
|
||||
fifoCPUWREN_1 <= '0';
|
||||
fifoCPUWREN_0 <= '0';
|
||||
|
||||
-- Preserve current enable state to detect activation.
|
||||
cpuLastEN <= (RDEN or WREN) and CS;
|
||||
|
||||
-- Detect a Chip Select state change signalling access.
|
||||
if cpuLastEN = '0' and (RDEN = '1' or WREN = '1') then
|
||||
|
||||
-- Organisation of the memory is as follows:
|
||||
--
|
||||
-- Bank: [(SDRAM_ADDR_BITS-1) .. (SDRAM_ADDR_BITS-1)] & [((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) .. (SDRAM_COLUMN_BITS+1)]
|
||||
-- Row: [(SDRAM_ADDR_BITS-2) .. (SDRAM_COLUMN_BITS+SDRAM_BANK_BITS)]
|
||||
-- Column: [(SDRAM_COLUMN_BITS downto 2)]
|
||||
-- The bank is split so that the Bank MSB splits the SDRAM in 2, upper and lower segment, this is because Stack normally resides in the top upper
|
||||
-- segment and code in the bottom lower segment. The remaining bank bits are split at the page level such that 2 or more pages residing in different
|
||||
-- banks are contiguous, hoping to gain a little performance benefit through having a wider spread for code caching and stack caching and write thru.
|
||||
--
|
||||
cpuBank <= to_integer(unsigned(bank));
|
||||
cpuRow <= row;
|
||||
cpuCol <= ADDR(SDRAM_COLUMN_BITS downto 2) & '0';
|
||||
|
||||
-- For write operations, we write direct to memory. If the data is in cache then a write-thru is performed to preserve the cached bank.
|
||||
if WREN = '1' then
|
||||
|
||||
-- Preset the write selects according to the CPU signals. Let Quartus optimize as easier to read seeing all mask values.
|
||||
if(WRITE_BYTE = '1') then
|
||||
case ADDR(1 downto 0) is
|
||||
when "00" =>
|
||||
cpuDQM <= "1000";
|
||||
cpuDataIn <= DATA_IN(WORD_8BIT_RANGE) & X"000000";
|
||||
if writeThru = '1' then
|
||||
fifoCPUWREN_3 <= '1';
|
||||
end if;
|
||||
when "01" =>
|
||||
cpuDQM <= "0100";
|
||||
cpuDataIn <= X"00" & DATA_IN(WORD_8BIT_RANGE) & X"0000";
|
||||
if writeThru = '1' then
|
||||
fifoCPUWREN_2 <= '1';
|
||||
end if;
|
||||
when "10" =>
|
||||
cpuDQM <= "0010";
|
||||
cpuDataIn <= X"0000" & DATA_IN(WORD_8BIT_RANGE) & X"00";
|
||||
if writeThru = '1' then
|
||||
fifoCPUWREN_1 <= '1';
|
||||
end if;
|
||||
when "11" =>
|
||||
cpuDQM <= "0001";
|
||||
cpuDataIn <= X"000000" & DATA_IN(WORD_8BIT_RANGE);
|
||||
if writeThru = '1' then
|
||||
fifoCPUWREN_0 <= '1';
|
||||
end if;
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
elsif(WRITE_HWORD = '1') then
|
||||
|
||||
case ADDR(1) is
|
||||
when '0' =>
|
||||
cpuDQM <= "1100";
|
||||
cpuDataIn <= DATA_IN(WORD_16BIT_RANGE) & X"0000";
|
||||
if writeThru = '1' then
|
||||
fifoCPUWREN_3 <= '1';
|
||||
fifoCPUWREN_2 <= '1';
|
||||
end if;
|
||||
when '1' =>
|
||||
cpuDQM <= "0011";
|
||||
cpuDataIn <= X"0000" & DATA_IN(WORD_16BIT_RANGE);
|
||||
if writeThru = '1' then
|
||||
fifoCPUWREN_1 <= '1';
|
||||
fifoCPUWREN_0 <= '1';
|
||||
end if;
|
||||
end case;
|
||||
|
||||
else
|
||||
-- Reads are always 32bit wide and if no part word signal is asserted, writes are 32bit.
|
||||
cpuDataIn <= DATA_IN(31 downto 0);
|
||||
cpuDQM <= "1111";
|
||||
if writeThru = '1' then
|
||||
fifoCPUWREN_3 <= '1';
|
||||
fifoCPUWREN_2 <= '1';
|
||||
fifoCPUWREN_1 <= '1';
|
||||
fifoCPUWREN_0 <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Set the flags, cpuBusy indicates to the SDRAM FSM to perform an operation, it also halts the CPU.
|
||||
cpuIsWriting <= WREN;
|
||||
cpuBusy <= '1';
|
||||
|
||||
-- For reads, if the row is cached then we just fall through to perform a read operation from cache otherwise the
|
||||
-- SDRAM needs to be instructed to read a page into cache before reading.
|
||||
--
|
||||
elsif cpuCachedBank(to_integer(unsigned(bank))) = '0' or cpuCachedRow(to_integer(unsigned(bank))) /= ADDR(SDRAM_ADDR_BITS-1) & ADDR((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1)) & row then
|
||||
|
||||
cpuCachedBank(to_integer(unsigned(bank))) <= '1';
|
||||
cpuCachedRow (to_integer(unsigned(bank))) <= ADDR(SDRAM_ADDR_BITS-1) & ADDR((SDRAM_COLUMN_BITS+SDRAM_BANK_BITS-1) downto (SDRAM_COLUMN_BITS+1)) & row;
|
||||
|
||||
-- Set the flags, cpuBusy indicates to the SDRAM FSM to perform an operation, it also halts the CPU.
|
||||
cpuBusy <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Note SDRAM activity via a previous/last signal.
|
||||
cpuDoneLast <= sdDone;
|
||||
|
||||
-- A change in the Done signal then we end the SDRAM request and release the CPU.
|
||||
if (cpuDoneLast xor sdDone) = '1' then
|
||||
cpuBusy <= '0';
|
||||
cpuIsWriting <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- System bus control signals.
|
||||
BUSY <= '1' when (cpuLastEN = '0' and (RDEN = '1' or WREN = '1')) else cpuBusy;
|
||||
SDRAM_READY <= sdIsReady;
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
-- Inferred Dual Port RAM.
|
||||
--
|
||||
-- The dual port ram is used to buffer a full page within the SDRAM, one buffer for each bank. The addressing is such
|
||||
-- that half of the banks appear in the lower segment of the address space and half in the top segment, the MSB of the
|
||||
-- SDRAM address is used for the split. This is to cater for stack where typically, on the ZPU, the stack would reside
|
||||
-- in the very top of memory working down and the applications would reside at the bottom of the memory working up.
|
||||
--
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- SDRAM Side of dual port RAM.
|
||||
-- For Read: fifoDataOutHi <= fifoCache_3(sdWriteColumnAddr)
|
||||
-- fifoDataOutLo <= fifoCache_0(sdWriteColumnAddr)
|
||||
-- For Write: fifoCache_3 _1 <= fifoDataIn when sdWriteColumnAddr(0) = '0'
|
||||
-- fifoCache_2 _0 <= fifoDataIn when sdWriteColumnAddr(0) = '1'
|
||||
-- fifoSdWREN must be asserted ('1') for write operations.
|
||||
process(ALL)
|
||||
variable cacheAddr : unsigned(SDRAM_COLUMN_BITS-2+SDRAM_BANK_BITS downto 0);
|
||||
begin
|
||||
-- Setup the address based on the index (sdWriteColumnAddr) and the bank (cpuBank) as the cache is linear for 4 banks.
|
||||
--
|
||||
cacheAddr := to_unsigned(cpuBank, SDRAM_BANK_BITS) & sdWriteColumnAddr(SDRAM_COLUMN_BITS-1 downto 1);
|
||||
|
||||
if rising_edge(SDRAM_CLK) then
|
||||
if fifoSdWREN_1 = '1' then
|
||||
fifoCache_3(to_integer(cacheAddr)) := fifoDataInHi(WORD_UPPER_16BIT_RANGE);
|
||||
fifoCache_2(to_integer(cacheAddr)) := fifoDataInHi(WORD_LOWER_16BIT_RANGE);
|
||||
else
|
||||
fifoDataOutHi(WORD_UPPER_16BIT_RANGE) <= fifoCache_3(to_integer(cacheAddr));
|
||||
fifoDataOutHi(WORD_LOWER_16BIT_RANGE) <= fifoCache_2(to_integer(cacheAddr));
|
||||
end if;
|
||||
|
||||
if fifoSdWREN_0 = '1' then
|
||||
fifoCache_1(to_integer(cacheAddr)) := fifoDataInLo(WORD_UPPER_16BIT_RANGE);
|
||||
fifoCache_0(to_integer(cacheAddr)) := fifoDataInLo(WORD_LOWER_16BIT_RANGE);
|
||||
else
|
||||
fifoDataOutLo(WORD_UPPER_16BIT_RANGE) <= fifoCache_1(to_integer(cacheAddr));
|
||||
fifoDataOutLo(WORD_LOWER_16BIT_RANGE) <= fifoCache_0(to_integer(cacheAddr));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- CPU Side of dual port RAM, byte addressable.
|
||||
-- For Read: DATA_OUT <= fifoCache(bank + ADDR(COLUMN_BITS .. 2))
|
||||
-- For Write: fifoCache(0..3) <= cpuDataIn
|
||||
process(ALL)
|
||||
variable cacheAddr : unsigned(SDRAM_COLUMN_BITS-2+SDRAM_BANK_BITS downto 0);
|
||||
begin
|
||||
-- Setup the address based on the column address bits, 32 bit aligned and the bank (cpuBank) as the cache is linear for 4 banks.
|
||||
--
|
||||
cacheAddr := to_unsigned(cpuBank, SDRAM_BANK_BITS) & unsigned(ADDR(SDRAM_COLUMN_BITS downto 2));
|
||||
|
||||
if rising_edge(CLK) then
|
||||
if fifoCPUWREN_3 = '1' then
|
||||
fifoCache_3(to_integer(cacheAddr)) := cpuDataIn(31 downto 24);
|
||||
else
|
||||
DATA_OUT((SDRAM_DATAWIDTH*2)-1 downto ((SDRAM_DATAWIDTH*2)-(SDRAM_DATAWIDTH/2))) <= fifoCache_3(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
|
||||
if fifoCPUWREN_2 = '1' then
|
||||
fifoCache_2(to_integer(cacheAddr)) := cpuDataIn(23 downto 16);
|
||||
else
|
||||
DATA_OUT(((SDRAM_DATAWIDTH*2)-(SDRAM_DATAWIDTH/2))-1 downto SDRAM_DATAWIDTH) <= fifoCache_2(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
|
||||
if fifoCPUWREN_1 = '1' then
|
||||
fifoCache_1(to_integer(cacheAddr)) := cpuDataIn(15 downto 8);
|
||||
else
|
||||
DATA_OUT(SDRAM_DATAWIDTH-1 downto SDRAM_DATAWIDTH/2) <= fifoCache_1(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
|
||||
if fifoCPUWREN_0 = '1' then
|
||||
fifoCache_0(to_integer(cacheAddr)) := cpuDataIn(7 downto 0);
|
||||
else
|
||||
DATA_OUT((SDRAM_DATAWIDTH/2)-1 downto 0) <= fifoCache_0(to_integer(unsigned(cacheAddr)));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end Structure;
|
||||
@@ -1,728 +0,0 @@
|
||||
------------------------------------------------------
|
||||
-- FSM for a SDRAM controller
|
||||
--
|
||||
-- Version 0.1 - Ready to simulate
|
||||
--
|
||||
-- Authors: Mike Field (hamster@snap.net.nz)
|
||||
-- Alvaro Lopes (alvieboy@alvie.com)
|
||||
--
|
||||
-- Feel free to use it however you would like, but
|
||||
-- just drop us an email to say thanks.
|
||||
-------------------------------------------------------
|
||||
library ieee;
|
||||
library pkgs;
|
||||
library work;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use work.zpu_soc_pkg.all;
|
||||
use work.zpu_pkg.all;
|
||||
|
||||
entity sdram_controller is
|
||||
generic (
|
||||
HIGH_BIT: integer := 24;
|
||||
MHZ: integer := 96;
|
||||
REFRESH_CYCLES: integer := 4096;
|
||||
ADDRESS_BITS: integer := 12
|
||||
);
|
||||
PORT (
|
||||
clock_100: in std_logic;
|
||||
clock_100_delayed_3ns: in std_logic;
|
||||
rst: in std_logic;
|
||||
|
||||
-- Signals to/from the SDRAM chip
|
||||
DRAM_ADDR : OUT STD_LOGIC_VECTOR (ADDRESS_BITS-1 downto 0);
|
||||
DRAM_BA : OUT STD_LOGIC_VECTOR (1 downto 0);
|
||||
DRAM_CAS_N : OUT STD_LOGIC;
|
||||
DRAM_CKE : OUT STD_LOGIC;
|
||||
DRAM_CLK : OUT STD_LOGIC;
|
||||
DRAM_CS_N : OUT STD_LOGIC;
|
||||
DRAM_DQ : INOUT STD_LOGIC_VECTOR(15 downto 0);
|
||||
DRAM_DQM : OUT STD_LOGIC_VECTOR(1 downto 0);
|
||||
DRAM_RAS_N : OUT STD_LOGIC;
|
||||
DRAM_WE_N : OUT STD_LOGIC;
|
||||
|
||||
pending: out std_logic;
|
||||
|
||||
--- Inputs from rest of the system
|
||||
address : IN STD_LOGIC_VECTOR (HIGH_BIT downto 2);
|
||||
req_read : IN STD_LOGIC;
|
||||
req_write : IN STD_LOGIC;
|
||||
data_out : OUT STD_LOGIC_VECTOR (31 downto 0);
|
||||
data_out_valid : OUT STD_LOGIC;
|
||||
data_in : IN STD_LOGIC_VECTOR (31 downto 0);
|
||||
data_mask : IN STD_LOGIC_VECTOR (3 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
|
||||
architecture rtl of sdram_controller is
|
||||
|
||||
type reg is record
|
||||
address : std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||||
bank : std_logic_vector( 1 downto 0);
|
||||
init_counter : unsigned(14 downto 0);
|
||||
rf_counter : integer;
|
||||
rf_pending : std_logic;
|
||||
rd_pending : std_logic;
|
||||
wr_pending : std_logic;
|
||||
act_row : std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||||
act_ba : std_logic_vector(1 downto 0);
|
||||
data_out_low : std_logic_vector(15 downto 0);
|
||||
req_addr_q : std_logic_vector(HIGH_BIT downto 2);
|
||||
req_data_write: std_logic_vector(31 downto 0);
|
||||
req_mask : std_logic_vector(3 downto 0);
|
||||
data_out_valid: std_logic;
|
||||
dq_masks : std_logic_vector(1 downto 0);
|
||||
tristate : std_logic;
|
||||
end record;
|
||||
|
||||
signal r : reg;
|
||||
signal n : reg;
|
||||
|
||||
signal rstate : std_logic_vector(8 downto 0);
|
||||
signal nstate : std_logic_vector(8 downto 0);
|
||||
signal rdata_write : std_logic_vector(15 downto 0);
|
||||
signal ndata_write : std_logic_vector(15 downto 0);
|
||||
|
||||
|
||||
-- Vectors for each SDRAM 'command'
|
||||
--- CS_N, RAS_N, CAS_N, WE_N
|
||||
constant cmd_nop : std_logic_vector(3 downto 0) := "0111";
|
||||
constant cmd_read : std_logic_vector(3 downto 0) := "0101"; -- Must be sure A10 is low.
|
||||
constant cmd_write : std_logic_vector(3 downto 0) := "0100";
|
||||
constant cmd_act : std_logic_vector(3 downto 0) := "0011";
|
||||
constant cmd_pre : std_logic_vector(3 downto 0) := "0010"; -- Must set A10 to '1'.
|
||||
constant cmd_ref : std_logic_vector(3 downto 0) := "0001";
|
||||
constant cmd_mrs : std_logic_vector(3 downto 0) := "0000"; -- Mode register set
|
||||
|
||||
-- State assignments
|
||||
constant s_init_nop_id: std_logic_vector(4 downto 0) := "00000";
|
||||
|
||||
constant s_init_nop : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_nop;
|
||||
constant s_init_pre : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_pre;
|
||||
constant s_init_ref : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_ref;
|
||||
constant s_init_mrs : std_logic_vector(8 downto 0) := s_init_nop_id & cmd_mrs;
|
||||
|
||||
constant s_idle_id: std_logic_vector(4 downto 0) := "00001";
|
||||
constant s_idle : std_logic_vector(8 downto 0) := s_idle_id & cmd_nop;
|
||||
|
||||
constant s_rf0_id: std_logic_vector(4 downto 0) := "00010";
|
||||
constant s_rf0 : std_logic_vector(8 downto 0) := s_rf0_id & cmd_ref;
|
||||
|
||||
constant s_rf1_id: std_logic_vector(4 downto 0) := "00011";
|
||||
constant s_rf1 : std_logic_vector(8 downto 0) := "00011" & cmd_nop;
|
||||
|
||||
constant s_rf2_id: std_logic_vector(4 downto 0) := "00100";
|
||||
constant s_rf2 : std_logic_vector(8 downto 0) := "00100" & cmd_nop;
|
||||
|
||||
constant s_rf3_id: std_logic_vector(4 downto 0) := "00101";
|
||||
constant s_rf3 : std_logic_vector(8 downto 0) := "00101" & cmd_nop;
|
||||
|
||||
constant s_rf4_id: std_logic_vector(4 downto 0) := "00110";
|
||||
constant s_rf4 : std_logic_vector(8 downto 0) := "00110" & cmd_nop;
|
||||
|
||||
constant s_rf5_id: std_logic_vector(4 downto 0) := "00111";
|
||||
constant s_rf5 : std_logic_vector(8 downto 0) := "00111" & cmd_nop;
|
||||
|
||||
|
||||
constant s_ra0_id: std_logic_vector(4 downto 0) := "01000";
|
||||
constant s_ra0 : std_logic_vector(8 downto 0) := "01000" & cmd_act;
|
||||
|
||||
constant s_ra1_id: std_logic_vector(4 downto 0) := "01001";
|
||||
constant s_ra1 : std_logic_vector(8 downto 0) := "01001" & cmd_nop;
|
||||
|
||||
constant s_ra2_id: std_logic_vector(4 downto 0) := "01010";
|
||||
constant s_ra2 : std_logic_vector(8 downto 0) := "01010" & cmd_nop;
|
||||
|
||||
|
||||
constant s_dr0_id: std_logic_vector(4 downto 0) := "01011";
|
||||
constant s_dr0 : std_logic_vector(8 downto 0) := "01011" & cmd_pre;
|
||||
|
||||
constant s_dr1_id: std_logic_vector(4 downto 0) := "01100";
|
||||
constant s_dr1 : std_logic_vector(8 downto 0) := "01100" & cmd_nop;
|
||||
|
||||
constant s_wr0_id: std_logic_vector(4 downto 0) := "01101";
|
||||
constant s_wr0 : std_logic_vector(8 downto 0) := "01101" & cmd_write;
|
||||
|
||||
constant s_wr1_id: std_logic_vector(4 downto 0) := "01110";
|
||||
constant s_wr1 : std_logic_vector(8 downto 0) := "01110" & cmd_nop;
|
||||
|
||||
constant s_wr2_id: std_logic_vector(4 downto 0) := "01111";
|
||||
constant s_wr2 : std_logic_vector(8 downto 0) := "01111" & cmd_nop;
|
||||
|
||||
constant s_wr3_id: std_logic_vector(4 downto 0) := "10000";
|
||||
constant s_wr3 : std_logic_vector(8 downto 0) := "10000" & cmd_write;
|
||||
|
||||
|
||||
constant s_rd0_id: std_logic_vector(4 downto 0) := "10001";
|
||||
constant s_rd0 : std_logic_vector(8 downto 0) := "10001" & cmd_read;
|
||||
|
||||
constant s_rd1_id: std_logic_vector(4 downto 0) := "10010";
|
||||
constant s_rd1 : std_logic_vector(8 downto 0) := "10010" & cmd_read;
|
||||
|
||||
constant s_rd2_id: std_logic_vector(4 downto 0) := "10011";
|
||||
constant s_rd2 : std_logic_vector(8 downto 0) := "10011" & cmd_nop;
|
||||
|
||||
constant s_rd3_id: std_logic_vector(4 downto 0) := "10100";
|
||||
constant s_rd3 : std_logic_vector(8 downto 0) := "10100" & cmd_read;
|
||||
|
||||
constant s_rd4_id: std_logic_vector(4 downto 0) := "10101";
|
||||
constant s_rd4 : std_logic_vector(8 downto 0) := "10101" & cmd_read;
|
||||
|
||||
constant s_rd5_id: std_logic_vector(4 downto 0) := "10110";
|
||||
constant s_rd5 : std_logic_vector(8 downto 0) := "10110" & cmd_read;
|
||||
|
||||
constant s_rd6_id: std_logic_vector(4 downto 0) := "10111";
|
||||
constant s_rd6 : std_logic_vector(8 downto 0) := "10111" & cmd_nop;
|
||||
|
||||
constant s_rd7_id: std_logic_vector(4 downto 0) := "11000";
|
||||
constant s_rd7 : std_logic_vector(8 downto 0) := "11000" & cmd_nop;
|
||||
|
||||
constant s_rd8_id: std_logic_vector(4 downto 0) := "11001";
|
||||
constant s_rd8 : std_logic_vector(8 downto 0) := "11001" & cmd_nop;
|
||||
|
||||
constant s_rd9_id: std_logic_vector(4 downto 0) := "11011";
|
||||
constant s_rd9 : std_logic_vector(8 downto 0) := "11011" & cmd_nop;
|
||||
|
||||
|
||||
constant s_drdr0_id: std_logic_vector(4 downto 0) := "11101";
|
||||
constant s_drdr0 : std_logic_vector(8 downto 0) := "11101" & cmd_pre;
|
||||
|
||||
constant s_drdr1_id: std_logic_vector(4 downto 0) := "11110";
|
||||
constant s_drdr1 : std_logic_vector(8 downto 0) := "11110" & cmd_nop;
|
||||
|
||||
constant s_drdr2_id: std_logic_vector(4 downto 0) := "11111";
|
||||
constant s_drdr2 : std_logic_vector(8 downto 0) := "11111" & cmd_nop;
|
||||
|
||||
signal addr_row : std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||||
signal addr_bank: std_logic_vector(1 downto 0);
|
||||
|
||||
constant COLUMN_HIGH: integer := HIGH_BIT - addr_row'LENGTH - addr_bank'LENGTH - 1; -- last 1 means 16 bit width
|
||||
|
||||
|
||||
signal addr_col : std_logic_vector(7 downto 0);
|
||||
signal captured : std_logic_vector(15 downto 0);
|
||||
signal busy: std_logic;
|
||||
|
||||
constant tOPD: time := 1.4 ns;
|
||||
constant tHZ: time := 8 ns;
|
||||
|
||||
signal dram_dq_dly : std_logic_vector(15 downto 0);
|
||||
|
||||
-- Debug only
|
||||
signal debug_cmd: std_logic_vector(3 downto 0);
|
||||
|
||||
constant RELOAD: integer := (((64000000/REFRESH_CYCLES)*MHZ)/1000) - 10;
|
||||
|
||||
attribute IOB: string;
|
||||
|
||||
signal i_DRAM_CS_N: std_logic;
|
||||
attribute IOB of i_DRAM_CS_N: signal is "true";
|
||||
|
||||
signal i_DRAM_RAS_N: std_logic;
|
||||
attribute IOB of i_DRAM_RAS_N: signal is "true";
|
||||
|
||||
signal i_DRAM_CAS_N: std_logic;
|
||||
attribute IOB of i_DRAM_CAS_N: signal is "true";
|
||||
|
||||
signal i_DRAM_WE_N: std_logic;
|
||||
attribute IOB of i_DRAM_WE_N: signal is "true";
|
||||
|
||||
signal i_DRAM_ADDR: std_logic_vector(ADDRESS_BITS-1 downto 0);
|
||||
attribute IOB of i_DRAM_ADDR: signal is "true";
|
||||
|
||||
signal i_DRAM_BA: std_logic_vector(1 downto 0);
|
||||
attribute IOB of i_DRAM_BA: signal is "true";
|
||||
|
||||
signal i_DRAM_DQM: std_logic_vector(1 downto 0);
|
||||
attribute IOB of i_DRAM_DQM: signal is "true";
|
||||
|
||||
attribute IOB of rdata_write: signal is "true";
|
||||
attribute IOB of captured: signal is "true";
|
||||
|
||||
signal i_DRAM_CLK: std_logic;
|
||||
|
||||
attribute fsm_encoding: string;
|
||||
attribute fsm_encoding of nstate: signal is "user";
|
||||
attribute fsm_encoding of rstate: signal is "user";
|
||||
|
||||
begin
|
||||
|
||||
debug_cmd <= rstate(3 downto 0);
|
||||
|
||||
-- Addressing is in 32 bit words - twice that of the DRAM width,
|
||||
-- so each burst of four access two system words.
|
||||
--addr_row <= address(23 downto 11);
|
||||
--addr_bank <= address(10 downto 9);
|
||||
process(r.req_addr_q)
|
||||
begin
|
||||
addr_bank <= r.req_addr_q(HIGH_BIT downto (HIGH_BIT-addr_bank'LENGTH)+1);
|
||||
-- (24-2) downto (24-2 - 2 - 13 - 1)
|
||||
-- 22 downto 6
|
||||
addr_row <= --r.req_addr_q(HIGH_BIT-addr_bank'LENGTH downto COLUMN_HIGH+2);
|
||||
r.req_addr_q(ADDRESS_BITS-1+9 downto 9);
|
||||
addr_col <= (others => '0');
|
||||
|
||||
addr_col <= --r.req_addr_q(COLUMN_HIGH+1 downto 2) & "0";
|
||||
r.req_addr_q(8 downto 2) & "0";
|
||||
end process;
|
||||
|
||||
clock: entity work.oddrff
|
||||
port map (
|
||||
D0 => '0',
|
||||
D1 => '1',
|
||||
O => i_DRAM_CLK,
|
||||
CLK => clock_100
|
||||
);
|
||||
|
||||
DRAM_CKE <= '1';
|
||||
|
||||
DRAM_CLK <= clock_100; -- transport i_DRAM_CLK after tOPD;
|
||||
|
||||
i_DRAM_CS_N <= transport rstate(3) after tOPD;
|
||||
DRAM_CS_N <= i_DRAM_CS_N;
|
||||
|
||||
i_DRAM_RAS_N <= transport rstate(2) after tOPD;
|
||||
DRAM_RAS_N <= i_DRAM_RAS_N;
|
||||
|
||||
i_DRAM_CAS_N <= transport rstate(1) after tOPD;
|
||||
DRAM_CAS_N <= i_DRAM_CAS_N;
|
||||
|
||||
i_DRAM_WE_N <= transport rstate(0) after tOPD;
|
||||
DRAM_WE_N <= i_DRAM_WE_N;
|
||||
|
||||
i_DRAM_ADDR <= transport r.address after tOPD;
|
||||
DRAM_ADDR <= i_DRAM_ADDR;
|
||||
|
||||
i_DRAM_BA <= transport r.bank after tOPD;
|
||||
DRAM_BA <= i_DRAM_BA;
|
||||
|
||||
i_DRAM_DQM <= transport r.dq_masks after tOPD;
|
||||
DRAM_DQM <= i_DRAM_DQM;
|
||||
|
||||
DATA_OUT <= r.data_out_low & captured;--r.data_out_low & captured;
|
||||
data_out_valid <= r.data_out_valid;
|
||||
|
||||
DRAM_DQ <= (others => 'Z') after tHZ when r.tristate='1' else rdata_write;
|
||||
|
||||
pending <= '1' when r.wr_pending='1' or r.rd_pending='1' else '0';
|
||||
|
||||
process (r, rstate, address, req_read, rdata_write, req_write, addr_row, addr_bank, addr_col, data_in, captured)
|
||||
begin
|
||||
-- copy the existing values
|
||||
n <= r;
|
||||
nstate <= rstate;
|
||||
ndata_write <= rdata_write;
|
||||
|
||||
if req_read = '1' then
|
||||
n.rd_pending <= '1';
|
||||
if r.rd_pending='0' then
|
||||
n.req_addr_q <= address;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if req_write = '1' then
|
||||
n.wr_pending <= '1';
|
||||
if r.wr_pending='0' then
|
||||
n.req_addr_q <= address;
|
||||
-- Queue data here
|
||||
n.req_data_write <= data_in;
|
||||
n.req_mask <= data_mask;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
n.dq_masks <= "11";
|
||||
|
||||
-- first off, do we need to perform a refresh cycle ASAP?
|
||||
if r.rf_counter = RELOAD then -- 781 = 64,000,000ns / 8192 / 10ns
|
||||
n.rf_counter <= 0;
|
||||
n.rf_pending <= '1';
|
||||
else
|
||||
-- only start looking for refreshes outside of the initialisation state.
|
||||
if not(rstate(8 downto 4) = s_init_nop(8 downto 4)) then
|
||||
n.rf_counter <= r.rf_counter + 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Set the data bus into HIZ, high and low bytes masked
|
||||
--DRAM_DQ <= (others => 'Z');
|
||||
n.tristate <= '0';
|
||||
|
||||
n.init_counter <= r.init_counter - 1;
|
||||
|
||||
--ndata_write <= (others => DontCareValue);
|
||||
|
||||
n.data_out_valid <= '0'; -- alvie- here, no ?
|
||||
|
||||
-- Process the FSM
|
||||
case rstate(8 downto 4) is
|
||||
when s_init_nop_id => --s_init_nop(8 downto 4) =>
|
||||
nstate <= s_init_nop;
|
||||
n.address <= (others => '0');
|
||||
n.bank <= (others => '0');
|
||||
n.act_ba <= (others => '0');
|
||||
n.rf_counter <= 0;
|
||||
-- n.data_out_valid <= '1'; -- alvie- not here
|
||||
|
||||
-- T-130, precharge all banks.
|
||||
if r.init_counter = "000000010000010" then
|
||||
nstate <= s_init_pre;
|
||||
n.address(10) <= '1';
|
||||
end if;
|
||||
|
||||
-- T-127, T-111, T-95, T-79, T-63, T-47, T-31, T-15, the 8 refreshes
|
||||
|
||||
if r.init_counter(14 downto 7) = 0 and r.init_counter(3 downto 0) = 15 then
|
||||
nstate <= s_init_ref;
|
||||
end if;
|
||||
|
||||
-- T-3, the load mode register
|
||||
if r.init_counter = 3 then
|
||||
nstate <= s_init_mrs;
|
||||
-- Mode register is as follows:
|
||||
-- resvd wr_b OpMd CAS=3 Seq bust=1
|
||||
n.address <= "00" & "0" & "00" & "011" & "0" & "000";
|
||||
-- resvd
|
||||
n.bank <= "00";
|
||||
end if;
|
||||
|
||||
-- T-1 The switch to the FSM (first command will be a NOP
|
||||
if r.init_counter = 1 then
|
||||
nstate <= s_idle;
|
||||
end if;
|
||||
|
||||
------------------------------
|
||||
-- The Idle section
|
||||
------------------------------
|
||||
when s_idle_id =>
|
||||
nstate <= s_idle;
|
||||
|
||||
-- do we have to activate a row?
|
||||
if r.rd_pending = '1' or r.wr_pending = '1' then
|
||||
nstate <= s_ra0;
|
||||
n.address <= addr_row;
|
||||
n.act_row <= addr_row;
|
||||
n.bank <= addr_bank;
|
||||
end if;
|
||||
|
||||
-- refreshes take priority over everything
|
||||
if r.rf_pending = '1' then
|
||||
nstate <= s_rf0;
|
||||
n.rf_pending <= '0';
|
||||
end if;
|
||||
------------------------------
|
||||
-- Row activation
|
||||
-- s_ra2 is also the "idle with active row" state and provides
|
||||
-- a resting point between operations on the same row
|
||||
------------------------------
|
||||
when s_ra0_id =>
|
||||
nstate <= s_ra1;
|
||||
when s_ra1_id =>
|
||||
nstate <= s_ra2;
|
||||
|
||||
|
||||
when s_ra2_id=>
|
||||
-- we can stay in this state until we have something to do
|
||||
nstate <= s_ra2;
|
||||
n.tristate<='0';
|
||||
|
||||
if r.rf_pending = '1' then
|
||||
nstate <= s_dr0;
|
||||
n.address(10) <= '1';
|
||||
else
|
||||
|
||||
-- If there is a read pending, deactivate the row
|
||||
if r.rd_pending = '1' or r.wr_pending = '1' then
|
||||
nstate <= s_dr0;
|
||||
n.address(10) <= '1';
|
||||
end if;
|
||||
|
||||
-- unless we have a read to perform on the same row? do that instead
|
||||
if r.rd_pending = '1' and r.act_row = addr_row and addr_bank=r.bank then
|
||||
nstate <= s_rd0;
|
||||
n.address <= (others => '0');
|
||||
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||||
n.bank <= addr_bank;
|
||||
n.act_ba <= addr_bank;
|
||||
n.dq_masks <= "00";
|
||||
n.rd_pending <= '0';
|
||||
--n.tristate<='1';
|
||||
end if;
|
||||
|
||||
-- unless we have a write on the same row? writes take priroty over reads
|
||||
if r.wr_pending = '1' and r.act_row = addr_row and addr_bank=r.bank then
|
||||
nstate <= s_wr0;
|
||||
n.address <= (others => '0');
|
||||
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||||
ndata_write <= r.req_data_write(31 downto 16);
|
||||
n.bank <= addr_bank;
|
||||
n.act_ba <= addr_bank;
|
||||
n.dq_masks<= not r.req_mask(3 downto 2);
|
||||
n.wr_pending <= '0';
|
||||
--n.tristate <= '0';
|
||||
end if;
|
||||
|
||||
|
||||
end if;
|
||||
-- nstate <= s_dr0;
|
||||
-- n.address(10) <= '1';
|
||||
-- n.rd_pending <= r.rd_pending;
|
||||
-- n.wr_pending <= r.wr_pending;
|
||||
--n.tristate <= '0';
|
||||
--end if;
|
||||
|
||||
------------------------------------------------------
|
||||
-- Deactivate the current row and return to idle state
|
||||
------------------------------------------------------
|
||||
when s_dr0_id =>
|
||||
nstate <= s_dr1;
|
||||
when s_dr1_id =>
|
||||
nstate <= s_idle;
|
||||
|
||||
------------------------------
|
||||
-- The Refresh section
|
||||
------------------------------
|
||||
when s_rf0_id =>
|
||||
nstate <= s_rf1;
|
||||
when s_rf1_id =>
|
||||
nstate <= s_rf2;
|
||||
when s_rf2_id =>
|
||||
nstate <= s_rf3;
|
||||
when s_rf3_id =>
|
||||
nstate <= s_rf4;
|
||||
when s_rf4_id =>
|
||||
nstate <= s_rf5;
|
||||
when s_rf5_id =>
|
||||
nstate <= s_idle;
|
||||
------------------------------
|
||||
-- The Write section
|
||||
------------------------------
|
||||
when s_wr0_id =>
|
||||
nstate <= s_wr3;
|
||||
n.bank <= addr_bank;
|
||||
n.address(0) <= '1';
|
||||
ndata_write <= r.req_data_write(15 downto 0);--data_in(31 downto 16);
|
||||
--DRAM_DQ <= rdata_write;
|
||||
n.dq_masks<= not r.req_mask(1 downto 0);
|
||||
n.tristate <= '0';
|
||||
|
||||
when s_wr1_id => null;
|
||||
when s_wr2_id =>
|
||||
nstate <= s_dr0;
|
||||
n.address(10) <= '1';
|
||||
|
||||
|
||||
when s_wr3_id =>
|
||||
-- Default to the idle+row active state
|
||||
nstate <= s_ra2;
|
||||
--DRAM_DQ <= rdata_write;
|
||||
n.data_out_valid<='1'; -- alvie- ack write
|
||||
n.tristate <= '0';
|
||||
n.dq_masks<= "11";
|
||||
|
||||
-- If there is a read or write then deactivate the row
|
||||
--if r.rd_pending = '1' or r.wr_pending = '1' then
|
||||
-- nstate <= s_dr0;
|
||||
-- n.address(10) <= '1';
|
||||
--end if;
|
||||
|
||||
-- But if there is a read pending in the same row, do that
|
||||
--if r.rd_pending = '1' and r.act_row = addr_row and r.act_ba = addr_bank then
|
||||
-- nstate <= s_rd0;
|
||||
-- n.address <= (others => '0');
|
||||
-- n.address(addr_col'HIGH downto 0) <= addr_col;
|
||||
-- n.bank <= addr_bank;
|
||||
-- --n.act_ba <= addr_bank;
|
||||
-- n.dq_masks <= "00";
|
||||
-- n.rd_pending <= '0';
|
||||
--end if;
|
||||
|
||||
-- unless there is a write pending in the same row, do that
|
||||
--if r.wr_pending = '1' and r.act_row = addr_row and r.act_ba = addr_bank then
|
||||
-- nstate <= s_wr0;
|
||||
-- n.address <= (others => '0');
|
||||
-- n.address(addr_col'HIGH downto 0) <= addr_col;
|
||||
-- n.bank <= addr_bank;
|
||||
--n.act_ba <= addr_bank;
|
||||
-- n.dq_masks<= "00";
|
||||
-- n.wr_pending <= '0';
|
||||
--end if;
|
||||
|
||||
-- But always try and refresh if one is pending!
|
||||
if r.rf_pending = '1' then
|
||||
nstate <= s_wr2; --dr0;
|
||||
--n.address(10) <= '1';
|
||||
end if;
|
||||
|
||||
------------------------------
|
||||
-- The Read section
|
||||
------------------------------
|
||||
when s_rd0_id => -- 10001
|
||||
nstate <= s_rd1;
|
||||
n.tristate<='1';
|
||||
n.dq_masks <= "00";
|
||||
n.address(0)<='1';
|
||||
|
||||
when s_rd1_id => -- 10010
|
||||
nstate <= s_rd2;
|
||||
n.dq_masks <= "00";
|
||||
n.tristate<='1';
|
||||
if r.rd_pending = '1' and r.act_row = addr_row and r.act_ba=addr_bank then
|
||||
|
||||
nstate <= s_rd3; -- Another request came, and we can pipeline -
|
||||
n.address <= (others => '0');
|
||||
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||||
n.bank <= addr_bank;
|
||||
n.act_ba <= addr_bank;
|
||||
n.dq_masks<= "00";
|
||||
n.rd_pending <= '0';
|
||||
|
||||
end if;
|
||||
|
||||
when s_rd2_id => -- 10011
|
||||
nstate <= s_rd7;
|
||||
n.dq_masks <= "00";
|
||||
n.tristate<='1';
|
||||
|
||||
|
||||
when s_rd3_id => -- 10100
|
||||
|
||||
nstate <= s_rd4;
|
||||
n.dq_masks <= "00";
|
||||
n.address(0) <= '1';
|
||||
n.tristate<='1';
|
||||
|
||||
|
||||
-- Data is still not ready...
|
||||
|
||||
when s_rd4_id => -- 10101
|
||||
nstate <= s_rd5;
|
||||
n.dq_masks <= "00";
|
||||
--n.address(0)<='1';
|
||||
n.tristate<='1';
|
||||
|
||||
if r.rd_pending = '1' and r.act_row = addr_row and r.act_ba=addr_bank then
|
||||
nstate <= s_rd5; -- Another request came, and we can pipeline -
|
||||
|
||||
n.address <= (others => '0');
|
||||
n.address(addr_col'HIGH downto 0) <= addr_col;
|
||||
n.bank <= addr_bank;
|
||||
n.act_ba <= addr_bank;
|
||||
n.dq_masks<= "00";
|
||||
n.rd_pending <= '0';
|
||||
|
||||
else
|
||||
nstate <= s_rd6; -- NOTE: not correct
|
||||
end if;
|
||||
|
||||
--if r.rf_pending = '1' then
|
||||
-- nstate <= s_drdr0;
|
||||
-- n.address(10) <= '1';
|
||||
-- n.rd_pending <= r.rd_pending; -- Keep request
|
||||
--end if;
|
||||
|
||||
|
||||
n.data_out_low <= captured;
|
||||
n.data_out_valid <= '1';
|
||||
|
||||
|
||||
when s_rd5_id =>
|
||||
-- If a refresh is pending then always deactivate the row
|
||||
--if r.rf_pending = '1' then
|
||||
-- nstate <= s_drdr0;
|
||||
-- n.address(10) <= '1';
|
||||
--end if;
|
||||
|
||||
n.address(0) <= '1';
|
||||
nstate <= s_rd4; -- Another request came, and we can pipeline -
|
||||
n.dq_masks <= "00";
|
||||
n.tristate<='1';
|
||||
|
||||
when s_rd6_id =>
|
||||
nstate <= s_rd7;
|
||||
n.dq_masks<= "00";
|
||||
n.tristate<='1';
|
||||
|
||||
when s_rd7_id =>
|
||||
nstate <= s_ra2;
|
||||
n.data_out_low <= captured;
|
||||
n.data_out_valid <= '1';
|
||||
n.tristate<='1';
|
||||
|
||||
when s_rd8_id => null;
|
||||
|
||||
when s_rd9_id => null;
|
||||
|
||||
-- The Deactivate row during read section
|
||||
------------------------------
|
||||
when s_drdr0_id =>
|
||||
nstate <= s_drdr1;
|
||||
when s_drdr1_id =>
|
||||
nstate <= s_drdr2;
|
||||
n.data_out_low <= captured;
|
||||
n.data_out_valid <= '1';
|
||||
when s_drdr2_id =>
|
||||
nstate <= s_idle;
|
||||
|
||||
if r.rf_pending = '1' then
|
||||
nstate <= s_rf0;
|
||||
end if;
|
||||
|
||||
if r.rd_pending = '1' or r.wr_pending = '1' then
|
||||
nstate <= s_ra0;
|
||||
n.address <= addr_row;
|
||||
n.act_row <= addr_row;
|
||||
n.bank <= addr_bank;
|
||||
end if;
|
||||
|
||||
when others =>
|
||||
nstate <= s_init_nop;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
--- The clock driven logic
|
||||
process (clock_100, n)
|
||||
begin
|
||||
if clock_100'event and clock_100 = '1' then
|
||||
if rst='1' then
|
||||
rstate <= (others => '0');
|
||||
r.address <= (others => '0');
|
||||
r.bank <= (others => '0');
|
||||
r.init_counter <= "100000000000000";
|
||||
-- synopsys translate_off
|
||||
r.init_counter <= "000000100000000";
|
||||
-- synopsys translate_on
|
||||
r.rf_counter <= 0;
|
||||
r.rf_pending <= '0';
|
||||
r.rd_pending <= '0';
|
||||
r.wr_pending <= '0';
|
||||
r.act_row <= (others => '0');
|
||||
r.data_out_low <= (others => '0');
|
||||
r.data_out_valid <= '0';
|
||||
r.dq_masks <= "11";
|
||||
r.tristate<='1';
|
||||
else
|
||||
r <= n;
|
||||
rstate <= nstate;
|
||||
rdata_write <= ndata_write;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
dram_dq_dly <= transport dram_dq after 3.6 ns;--1.9 ns;
|
||||
|
||||
-- process (clock_100_delayed_3ns, dram_dq_dly)
|
||||
-- begin
|
||||
-- if clock_100_delayed_3ns'event and clock_100_delayed_3ns = '1' then
|
||||
-- captured <= dram_dq_dly;
|
||||
-- end if;
|
||||
-- end process;
|
||||
|
||||
process (clock_100_delayed_3ns)
|
||||
begin
|
||||
if falling_edge(clock_100_delayed_3ns) then
|
||||
captured <= dram_dq_dly;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end rtl;
|
||||
@@ -41,7 +41,8 @@ entity uart is
|
||||
generic (
|
||||
RX_FIFO_BIT_DEPTH : integer := 10;
|
||||
TX_FIFO_BIT_DEPTH : integer := 8;
|
||||
COUNTER_BITS : natural := 16
|
||||
COUNTER_BITS : natural := 16;
|
||||
BAUDCLK_FREQUENCY : integer := SYSTEM_FREQUENCY -- Baud rate clock frequency, used so a program can determine the clocking frequency and set divisor accordingly.
|
||||
);
|
||||
port (
|
||||
-- CPU Interface
|
||||
@@ -456,9 +457,9 @@ begin
|
||||
DATA_OUT( RX_FIFO_BIT_DEPTH-1 downto 0) <= std_logic_vector(RX_FIFO_WR_ADDR - RX_FIFO_RD_ADDR);
|
||||
DATA_OUT(16+TX_FIFO_BIT_DEPTH-1 downto 16) <= std_logic_vector(TX_FIFO_WR_ADDR - TX_FIFO_RD_ADDR);
|
||||
|
||||
-- Baud Rate Generator setting.
|
||||
-- System clock frequency.
|
||||
when "11" =>
|
||||
DATA_OUT <= std_logic_vector(TX_CLOCK_DIVISOR & RX_CLOCK_DIVISOR);
|
||||
DATA_OUT <= std_logic_vector(to_unsigned(BAUDCLK_FREQUENCY, wordSize));
|
||||
end case;
|
||||
end process;
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.7 MiB |
BIN
docs/ScreenZPU4.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/ZPUSDRAMPerformance.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/ZPUSDRAMPerformnceCached.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/ZPUWBSDRAMPerformance.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
docs/ZPUWBSDRAMPerformnceCached.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
@@ -74,16 +74,20 @@ uint32_t app(uint32_t param1, uint32_t param2)
|
||||
|
||||
if (!xatoi(&ptr, &startAddr))
|
||||
{
|
||||
if(cfgSoC->implInsnBRAM) { startAddr = cfgSoC->addrInsnBRAM; }
|
||||
else if(cfgSoC->implBRAM) { startAddr = cfgSoC->addrBRAM; }
|
||||
else if(cfgSoC->implRAM || cfgSoC->implDRAM) { startAddr = cfgSoC->addrRAM; }
|
||||
if(cfgSoC->implInsnBRAM) { startAddr = cfgSoC->addrInsnBRAM; }
|
||||
else if(cfgSoC->implBRAM) { startAddr = cfgSoC->addrBRAM; }
|
||||
else if(cfgSoC->implRAM) { startAddr = cfgSoC->addrRAM; }
|
||||
else if(cfgSoC->implSDRAM) { startAddr = cfgSoC->addrSDRAM; }
|
||||
else if(cfgSoC->implWBSDRAM) { startAddr = cfgSoC->addrWBSDRAM; }
|
||||
else { startAddr = cfgSoC->stackStartAddr - 512; }
|
||||
}
|
||||
if (!xatoi(&ptr, &endAddr))
|
||||
{
|
||||
if(cfgSoC->implInsnBRAM) { endAddr = cfgSoC->sizeInsnBRAM; }
|
||||
else if(cfgSoC->implBRAM) { endAddr = cfgSoC->sizeBRAM; }
|
||||
else if(cfgSoC->implRAM || cfgSoC->implDRAM) { endAddr = cfgSoC->sizeRAM; }
|
||||
if(cfgSoC->implInsnBRAM) { endAddr = cfgSoC->sizeInsnBRAM; }
|
||||
else if(cfgSoC->implBRAM) { endAddr = cfgSoC->sizeBRAM; }
|
||||
else if(cfgSoC->implRAM) { endAddr = cfgSoC->sizeRAM; }
|
||||
else if(cfgSoC->implSDRAM) { endAddr = cfgSoC->sizeSDRAM; }
|
||||
else if(cfgSoC->implWBSDRAM) { endAddr = cfgSoC->sizeWBSDRAM; }
|
||||
else { endAddr = cfgSoC->stackStartAddr + 8; }
|
||||
}
|
||||
if (!xatoi(&ptr, &bitWidth) || (bitWidth != 8 && bitWidth != 16 && bitWidth != 32))
|
||||
|
||||
@@ -94,7 +94,7 @@ uint32_t app(uint32_t param1, uint32_t param2)
|
||||
xgets(line, sizeof line);
|
||||
ptr = line;
|
||||
if (*ptr == '.') break;
|
||||
if (*ptr < ' ') { addr++; continue; }
|
||||
| < | ||||