diff --git a/.gitignore b/.gitignore index a881c83..51042a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,22 @@ -*.bak -output_files/ -db/ -greybox_tmp/ -incremental_db/ -simulation/ +board/**/*.asm.* +board/**/*.done +board/**/*.eda.* +board/**/*.fit.* +board/**/*.flow.* +board/**/*.map.* +board/**/*.pin +board/**/*.pof +board/**/*.qpf +board/**/*.qsf +board/**/*.sof +board/**/*.psf +board/**/*.sta.* +board/**/incremental_db/ +board/**/simulation/ +db/ +greybox_tmp/ +incremental_db/ +pll.qip +simulation/ +**/**/*.bak + diff --git a/README.md b/README.md index b6988c5..5420b8b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ -socz80-de0 -========== +socz80-altera +=============== -This is a port of Will Sowerbutts' socz80 retro microcomputer (http://sowerbutts.com/socz80) for the Tersasic DE0 board based on the DE0 nano port from https://github.com/slp/socz80-de0_nano. +This is a port of Will Sowerbutts' socz80 retro microcomputer (http://sowerbutts.com/socz80) for Altera FPGA boards, currently supporting DE0, DE0-nano, DE2 and DE2-70 from Terasic. +Original version come from https://github.com/slp/socz80-altera Building ======== @@ -21,5 +22,5 @@ TODO * Video Out and PS2 for a keyboard could be also a nice entry. * Currently the 4 hex digit are used to show the CPU PC, but I will also create an IO device to show on them the value you want * Also add all the SW switch and Button 1 and 2 to GPI and the LED to GPO minus the one used to display the CPU status. and Button 0 is used for Reset. -* The original design was developed for a Papilo Pro board, which feautres a reasonable amount of non volatile memory onboard. The DE0 have a flash device, it may be nice to allow to map it to memory. Not sure if allow write to it is a good idea. +* The original design was developed for a Papilo Pro board, which featres a reasonable amount of non volatile memory onboard. The DE0 have a flash device, it may be nice to allow to map it to memory. Not sure if allow write to it is a good idea. * Also the two GPIO header could be added to the IO mapping. diff --git a/Makefile b/board/de0/Makefile similarity index 76% rename from Makefile rename to board/de0/Makefile index f62e7ea..164ed54 100644 --- a/Makefile +++ b/board/de0/Makefile @@ -20,8 +20,8 @@ sta: asm quartus_sta $(QUARTUS_OPTIONS) $(DESIGN_NAME) load: asm - quartus_pgm --mode=jtag -o p\;output_files/$(DESIGN_NAME).sof + quartus_pgm --mode=jtag -o p\;$(DESIGN_NAME).sof loadonly: quartus_sh $(QUARTUS_OPTIONS) - quartus_pgm --mode=jtag -o p\;output_files/$(DESIGN_NAME).sof \ No newline at end of file + quartus_pgm --mode=jtag -o p\;$(DESIGN_NAME).sof \ No newline at end of file diff --git a/de0.tcl b/board/de0/de0.tcl similarity index 95% rename from de0.tcl rename to board/de0/de0.tcl index bb87274..be16d83 100644 --- a/de0.tcl +++ b/board/de0/de0.tcl @@ -62,28 +62,31 @@ if {$make_assignments} { 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)" # VHDL Files - set_global_assignment -name VHDL_FILE vhdl/DE0_SEG7.vhd - set_global_assignment -name VHDL_FILE vhdl/uart_interface.vhd - set_global_assignment -name VHDL_FILE vhdl/uart.vhd - set_global_assignment -name VHDL_FILE vhdl/top_level.vhd - set_global_assignment -name VHDL_FILE vhdl/timer.vhd - set_global_assignment -name VHDL_FILE vhdl/T80se.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_Reg.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_Pack.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_MCode.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_ALU.vhd - set_global_assignment -name VHDL_FILE vhdl/T80.vhd - set_global_assignment -name VHDL_FILE vhdl/SSRAM.vhd - set_global_assignment -name VHDL_FILE vhdl/SDRAM_Controller.vhd - set_global_assignment -name VHDL_FILE vhdl/pll.vhd - set_global_assignment -name VHDL_FILE vhdl/MonZ80.vhd - set_global_assignment -name VHDL_FILE vhdl/MMU.vhd - set_global_assignment -name VHDL_FILE vhdl/gpio.vhd - set_global_assignment -name VHDL_FILE vhdl/fifo.vhd - set_global_assignment -name VHDL_FILE vhdl/DRAM.vhd - set_global_assignment -name VHDL_FILE vhdl/spimaster.vhd - set_global_assignment -name VHDL_FILE vhdl/clkscale.vhd - set_global_assignment -name VHDL_FILE vhdl/Z80cpu.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de0/DE0_SEG7.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart_interface.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de0/top_level_de0.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/timer.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80se.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Reg.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Pack.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_MCode.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_ALU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/SSRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de0/SDRAM_Controller.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de0/pll_de0.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MonZ80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MMU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/gpio.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/fifo.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/DRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/spimaster.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/clkscale.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/Z80cpu.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K36.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K9.vhd + set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top # Assign Port to IOs diff --git a/board/de0_nano/Makefile b/board/de0_nano/Makefile new file mode 100644 index 0000000..c2b2a69 --- /dev/null +++ b/board/de0_nano/Makefile @@ -0,0 +1,23 @@ +DESIGN_NAME = de0_nano +QUARTUS_OPTIONS = + + +all: asm + +project: $(TCL_FILE) + quartus_sh $(QUARTUS_OPTIONS) -t $(DESIGN_NAME).tcl + +map: project + quartus_map $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +fit: map + quartus_fit $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +asm: fit + quartus_asm $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +sta: asm + quartus_sta $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +load: asm + quartus_pgm --mode=jtag -o p\;$(DESIGN_NAME).sof diff --git a/de0_nano.tcl b/board/de0_nano/de0_nano.tcl similarity index 87% rename from de0_nano.tcl rename to board/de0_nano/de0_nano.tcl index 7b8108c..46e512d 100644 --- a/de0_nano.tcl +++ b/board/de0_nano/de0_nano.tcl @@ -56,26 +56,28 @@ if {$make_assignments} { 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)" set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V" - set_global_assignment -name VHDL_FILE vhdl/DRAM.vhd - set_global_assignment -name VHDL_FILE vhdl/SDRAM_Controller.vhd - set_global_assignment -name VHDL_FILE vhdl/gpio.vhd - set_global_assignment -name VHDL_FILE vhdl/T80.vhd - set_global_assignment -name VHDL_FILE vhdl/top_level.vhd - set_global_assignment -name VHDL_FILE vhdl/Z80cpu.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_Pack.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_ALU.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_MCode.vhd - set_global_assignment -name VHDL_FILE vhdl/T80_Reg.vhd - set_global_assignment -name VHDL_FILE vhdl/T80se.vhd - set_global_assignment -name VHDL_FILE vhdl/MMU.vhd - set_global_assignment -name VHDL_FILE vhdl/MonZ80.vhd - set_global_assignment -name VHDL_FILE vhdl/SSRAM.vhd - set_global_assignment -name VHDL_FILE vhdl/uart_interface.vhd - set_global_assignment -name VHDL_FILE vhdl/fifo.vhd - set_global_assignment -name VHDL_FILE vhdl/uart.vhd - set_global_assignment -name VHDL_FILE vhdl/timer.vhd - set_global_assignment -name VHDL_FILE vhdl/pll.vhd - set_global_assignment -name VHDL_FILE vhdl/clkscale.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de0_nano/SDRAM_Controller.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/DRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/gpio.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de0_nano/top_level_de0_nano.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/Z80cpu.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Pack.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_ALU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_MCode.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Reg.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80se.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MMU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MonZ80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/SSRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart_interface.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/fifo.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/timer.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de0_nano/pll_de0_nano.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/clkscale.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K36.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K9.vhd set_location_assignment PIN_J15 -to rst_n_pad_i set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to rst_n_pad_i set_location_assignment PIN_R8 -to sys_clk_pad_i @@ -199,4 +201,4 @@ if {$make_assignments} { if {$need_to_close_project} { project_close } -} +} \ No newline at end of file diff --git a/board/de2/Makefile b/board/de2/Makefile new file mode 100644 index 0000000..ba67f7d --- /dev/null +++ b/board/de2/Makefile @@ -0,0 +1,23 @@ +DESIGN_NAME = de2 +QUARTUS_OPTIONS = + + +all: asm + +project: $(TCL_FILE) + quartus_sh $(QUARTUS_OPTIONS) -t $(DESIGN_NAME).tcl + +map: project + quartus_map $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +fit: map + quartus_fit $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +asm: fit + quartus_asm $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +sta: asm + quartus_sta $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +load: asm + quartus_pgm --mode=jtag -o p\;$(DESIGN_NAME).sof diff --git a/board/de2/de2.tcl b/board/de2/de2.tcl new file mode 100644 index 0000000..6687eba --- /dev/null +++ b/board/de2/de2.tcl @@ -0,0 +1,203 @@ +# Copyright (C) 1991-2013 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. + +# Quartus II: Generate Tcl File for Project +# File: de2.tcl +# Generated on: Sat Sep 6 02:27:17 2014 + +# Load Quartus II Tcl Project package +package require ::quartus::project + +set need_to_close_project 0 +set make_assignments 1 + +# Check that the right project is open +if {[is_project_open]} { + if {[string compare $quartus(project) "de2"]} { + puts "Project de2 is not open" + set make_assignments 0 + } +} else { + # Only open if not already open + if {[project_exists de2]} { + project_open -revision de2 de2 + } else { + project_new -revision de2 de2 + } + set need_to_close_project 1 +} + +# Make assignments +if {$make_assignments} { + set_global_assignment -name FAMILY "Cyclone II" + set_global_assignment -name DEVICE EP2C35F672C6 + set_global_assignment -name TOP_LEVEL_ENTITY top_level + set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1 + set_global_assignment -name PROJECT_CREATION_TIME_DATE "19:30:55 AUGUST 28, 2014" + set_global_assignment -name LAST_QUARTUS_VERSION 13.1 + 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 PARTITION_NETLIST_TYPE SOURCE -section_id Top + set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top + set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top + set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 + set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 + 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)" + set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V" + set_global_assignment -name VHDL_FILE ../../vhdl/board/de2/SDRAM_Controller.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/DRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/gpio.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de2/top_level_de2.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/Z80cpu.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Pack.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_ALU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_MCode.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Reg.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80se.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MMU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MonZ80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/SSRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart_interface.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/fifo.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/timer.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de2/pll_de2.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/clkscale.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K36.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K9.vhd + + set_location_assignment PIN_G26 -to rst_n_pad_i + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to rst_n_pad_i + set_location_assignment PIN_N2 -to sys_clk_pad_i + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sys_clk_pad_i + set_location_assignment PIN_C25 -to serial_rx + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to serial_rx + set_location_assignment PIN_B25 -to serial_tx + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to serial_tx + set_location_assignment PIN_AE23 -to leds[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[0] + set_location_assignment PIN_AF23 -to leds[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[1] + set_location_assignment PIN_AB21 -to leds[2] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[2] + set_location_assignment PIN_AC22 -to leds[3] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[3] + set_location_assignment PIN_AD22 -to leds[4] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[4] + set_location_assignment PIN_T6 -to SDRAM_ADDR[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[0] + set_location_assignment PIN_V4 -to SDRAM_ADDR[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[1] + set_location_assignment PIN_V3 -to SDRAM_ADDR[2] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[2] + set_location_assignment PIN_W2 -to SDRAM_ADDR[3] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[3] + set_location_assignment PIN_W1 -to SDRAM_ADDR[4] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[4] + set_location_assignment PIN_U6 -to SDRAM_ADDR[5] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[5] + set_location_assignment PIN_U7 -to SDRAM_ADDR[6] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[6] + set_location_assignment PIN_U5 -to SDRAM_ADDR[7] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[7] + set_location_assignment PIN_W4 -to SDRAM_ADDR[8] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[8] + set_location_assignment PIN_W3 -to SDRAM_ADDR[9] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[9] + set_location_assignment PIN_Y1 -to SDRAM_ADDR[10] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[10] + set_location_assignment PIN_V5 -to SDRAM_ADDR[11] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[11] + set_location_assignment PIN_V6 -to SDRAM_DQ[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[0] + set_location_assignment PIN_AA2 -to SDRAM_DQ[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[1] + set_location_assignment PIN_AA1 -to SDRAM_DQ[2] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[2] + set_location_assignment PIN_Y3 -to SDRAM_DQ[3] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[3] + set_location_assignment PIN_Y4 -to SDRAM_DQ[4] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[4] + set_location_assignment PIN_R8 -to SDRAM_DQ[5] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[5] + set_location_assignment PIN_T8 -to SDRAM_DQ[6] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[6] + set_location_assignment PIN_V7 -to SDRAM_DQ[7] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[7] + set_location_assignment PIN_W6 -to SDRAM_DQ[8] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[8] + set_location_assignment PIN_AB2 -to SDRAM_DQ[9] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[9] + set_location_assignment PIN_AB1 -to SDRAM_DQ[10] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[10] + set_location_assignment PIN_AA4 -to SDRAM_DQ[11] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[11] + set_location_assignment PIN_AA3 -to SDRAM_DQ[12] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[12] + set_location_assignment PIN_AC2 -to SDRAM_DQ[13] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[13] + set_location_assignment PIN_AC1 -to SDRAM_DQ[14] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[14] + set_location_assignment PIN_AA5 -to SDRAM_DQ[15] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[15] + set_location_assignment PIN_AD2 -to SDRAM_DQM[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQM[0] + set_location_assignment PIN_Y5 -to SDRAM_DQM[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQM[1] + set_location_assignment PIN_AE2 -to SDRAM_BA[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[0] + set_location_assignment PIN_AE3 -to SDRAM_BA[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[1] + set_location_assignment PIN_AB3 -to SDRAM_nCAS + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_nCAS + set_location_assignment PIN_AA6 -to SDRAM_CKE + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CKE + set_location_assignment PIN_AC3 -to SDRAM_CS + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CS + set_location_assignment PIN_AB4 -to SDRAM_nRAS + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_nRAS + set_location_assignment PIN_AD3 -to SDRAM_nWE + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_nWE + set_location_assignment PIN_AA7 -to SDRAM_CLK + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CLK + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_command" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_address" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_dqm" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_cke" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_bank" + set_instance_assignment -name FAST_INPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_data" + set_instance_assignment -name FAST_INPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|captured_data" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_ADDR + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_CKE + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_CLK + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_CS + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQM + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ + set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ + set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top + + # Commit assignments + export_assignments + + # Close project + if {$need_to_close_project} { + project_close + } +} diff --git a/board/de2_70/Makefile b/board/de2_70/Makefile new file mode 100644 index 0000000..c237e0b --- /dev/null +++ b/board/de2_70/Makefile @@ -0,0 +1,23 @@ +DESIGN_NAME = de2_70 +QUARTUS_OPTIONS = + + +all: asm + +project: $(TCL_FILE) + quartus_sh $(QUARTUS_OPTIONS) -t $(DESIGN_NAME).tcl + +map: project + quartus_map $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +fit: map + quartus_fit $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +asm: fit + quartus_asm $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +sta: asm + quartus_sta $(QUARTUS_OPTIONS) $(DESIGN_NAME) + +load: asm + quartus_pgm --mode=jtag -o p\;$(DESIGN_NAME).sof diff --git a/board/de2_70/de2_70.tcl b/board/de2_70/de2_70.tcl new file mode 100644 index 0000000..a2db448 --- /dev/null +++ b/board/de2_70/de2_70.tcl @@ -0,0 +1,204 @@ +# Copyright (C) 1991-2013 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. + +# Quartus II: Generate Tcl File for Project +# File: de2_70.tcl +# Generated on: Sat Sep 6 02:27:17 2014 + +# Load Quartus II Tcl Project package +package require ::quartus::project + +set need_to_close_project 0 +set make_assignments 1 + +# Check that the right project is open +if {[is_project_open]} { + if {[string compare $quartus(project) "de2_70"]} { + puts "Project de2_70 is not open" + set make_assignments 0 + } +} else { + # Only open if not already open + if {[project_exists de2_70]} { + project_open -revision de2_70 de2_70 + } else { + project_new -revision de2_70 de2_70 + } + set need_to_close_project 1 +} + +# Make assignments +if {$make_assignments} { + set_global_assignment -name FAMILY "Cyclone II" + set_global_assignment -name DEVICE EP2C70F896C6 + set_global_assignment -name TOP_LEVEL_ENTITY top_level + set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1 + set_global_assignment -name PROJECT_CREATION_TIME_DATE "19:30:55 AUGUST 28, 2014" + set_global_assignment -name LAST_QUARTUS_VERSION 13.1 + 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 PARTITION_NETLIST_TYPE SOURCE -section_id Top + set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top + set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top + set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 + set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 + 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)" + set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V" + set_global_assignment -name VHDL_FILE ../../vhdl/board/de2_70/SDRAM_Controller.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/DRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/gpio.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de2_70/top_level_de2_70.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/Z80cpu.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Pack.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_ALU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_MCode.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80_Reg.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/T80se.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MMU.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/MonZ80.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/SSRAM.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart_interface.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/fifo.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/uart.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/timer.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/board/de2_70/pll_de2_70.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/clkscale.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K36.vhd + set_global_assignment -name VHDL_FILE ../../vhdl/RAM4K9.vhd + set_location_assignment PIN_T29 -to rst_n_pad_i + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to rst_n_pad_i + set_location_assignment PIN_AD15 -to sys_clk_pad_i + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sys_clk_pad_i + set_location_assignment PIN_D21 -to serial_rx + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to serial_rx + set_location_assignment PIN_E21 -to serial_tx + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to serial_tx + set_location_assignment PIN_AJ6 -to leds[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[0] + set_location_assignment PIN_AK5 -to leds[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[1] + set_location_assignment PIN_AJ5 -to leds[2] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[2] + set_location_assignment PIN_AJ4 -to leds[3] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[3] + set_location_assignment PIN_AK3 -to leds[4] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds[4] + set_location_assignment PIN_AA4 -to SDRAM_ADDR[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[0] + set_location_assignment PIN_AA5 -to SDRAM_ADDR[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[1] + set_location_assignment PIN_AA6 -to SDRAM_ADDR[2] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[2] + set_location_assignment PIN_AB5 -to SDRAM_ADDR[3] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[3] + set_location_assignment PIN_AB7 -to SDRAM_ADDR[4] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[4] + set_location_assignment PIN_AC4 -to SDRAM_ADDR[5] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[5] + set_location_assignment PIN_AC5 -to SDRAM_ADDR[6] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[6] + set_location_assignment PIN_AC6 -to SDRAM_ADDR[7] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[7] + set_location_assignment PIN_AD4 -to SDRAM_ADDR[8] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[8] + set_location_assignment PIN_AC7 -to SDRAM_ADDR[9] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[9] + set_location_assignment PIN_Y8 -to SDRAM_ADDR[10] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[10] + set_location_assignment PIN_AE4 -to SDRAM_ADDR[11] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[11] + set_location_assignment PIN_AF4 -to SDRAM_ADDR[12] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_ADDR[12] + set_location_assignment PIN_AC1 -to SDRAM_DQ[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[0] + set_location_assignment PIN_AC2 -to SDRAM_DQ[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[1] + set_location_assignment PIN_AC3 -to SDRAM_DQ[2] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[2] + set_location_assignment PIN_AD1 -to SDRAM_DQ[3] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[3] + set_location_assignment PIN_AD2 -to SDRAM_DQ[4] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[4] + set_location_assignment PIN_AD3 -to SDRAM_DQ[5] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[5] + set_location_assignment PIN_AE1 -to SDRAM_DQ[6] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[6] + set_location_assignment PIN_AE2 -to SDRAM_DQ[7] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[7] + set_location_assignment PIN_AE3 -to SDRAM_DQ[8] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[8] + set_location_assignment PIN_AF1 -to SDRAM_DQ[9] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[9] + set_location_assignment PIN_AF2 -to SDRAM_DQ[10] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[10] + set_location_assignment PIN_AF3 -to SDRAM_DQ[11] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[11] + set_location_assignment PIN_AG2 -to SDRAM_DQ[12] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[12] + set_location_assignment PIN_AG3 -to SDRAM_DQ[13] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[13] + set_location_assignment PIN_AH1 -to SDRAM_DQ[14] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[14] + set_location_assignment PIN_AH2 -to SDRAM_DQ[15] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQ[15] + set_location_assignment PIN_V9 -to SDRAM_DQM[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQM[0] + set_location_assignment PIN_AB6 -to SDRAM_DQM[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_DQM[1] + set_location_assignment PIN_AA9 -to SDRAM_BA[0] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[0] + set_location_assignment PIN_AA10 -to SDRAM_BA[1] + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_BA[1] + set_location_assignment PIN_W10 -to SDRAM_nCAS + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_nCAS + set_location_assignment PIN_AA8 -to SDRAM_CKE + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CKE + set_location_assignment PIN_Y10 -to SDRAM_CS + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CS + set_location_assignment PIN_Y9 -to SDRAM_nRAS + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_nRAS + set_location_assignment PIN_W9 -to SDRAM_nWE + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_nWE + set_location_assignment PIN_AD6 -to SDRAM_CLK + set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_CLK + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_command" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_address" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_dqm" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_cke" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_bank" + set_instance_assignment -name FAST_INPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|iob_data" + set_instance_assignment -name FAST_INPUT_REGISTER ON -to "DRAM:dram|SDRAM_Controller:sdram_ctrl|captured_data" + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_ADDR + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_CKE + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_CLK + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_CS + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQM + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE + set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ + set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ + set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top + + # Commit assignments + export_assignments + + # Close project + if {$need_to_close_project} { + project_close + } +} diff --git a/vhdl/DRAM.vhd b/vhdl/DRAM.vhd index 5d4cf4e..09ddcb2 100644 --- a/vhdl/DRAM.vhd +++ b/vhdl/DRAM.vhd @@ -112,13 +112,21 @@ architecture behaviour of DRAM is signal current_state : controller_state; signal next_state : controller_state; + -- here's the cache memory signals + signal cache_line_memory_write_enable : std_logic; + signal cache_line_memory_data_in : std_logic_vector(35 downto 0); -- 35 downto 32: validity bits; 31 downto 0: four data bytes + signal cache_line_memory_data_out : std_logic_vector(35 downto 0); + signal cache_tag_memory_write_enable : std_logic; + signal cache_tag_memory_data_in : std_logic_vector(8 downto 0); + signal cache_tag_memory_data_out : std_logic_vector(8 downto 0); + -- break up the incoming physical address alias address_byte : std_logic_vector(1 downto 0) is mem_address(1 downto 0); alias address_line : std_logic_vector(11 downto 0) is mem_address(13 downto 2); alias address_tag : std_logic_vector(8 downto 0) is mem_address(22 downto 14); alias address_word : std_logic_vector(20 downto 0) is mem_address(22 downto 2); -- mem_address(23) and mem_address(24) are unused in this design - + alias cache_inhibit : std_logic is mem_address(24); begin -- this should be based on the generic, really @@ -142,9 +150,14 @@ begin next_state <= st_idle; -- come back next cycle! else - cmd_enable <= '1'; - mem_wait <= '1'; - next_state <= st_read; + if cache_hit = '1' then + mem_wait <= '0'; + next_state <= st_read_done; + else + cmd_enable <= '1'; + mem_wait <= '1'; + next_state <= st_read; + end if; end if; elsif req_write = '1' then if word_changed = '1' then @@ -176,14 +189,14 @@ begin -- this kind of implies that they gave up on us? next_state <= st_idle; end if; - mem_wait <= (not sdram_data_out_ready); + mem_wait <= (not sdram_data_out_ready) and (not cache_hit); when st_read_done => if cs = '1' and req_read = '1' then next_state <= st_read_done; else next_state <= st_idle; end if; - mem_wait <= (not sdram_data_out_ready); + mem_wait <= (not sdram_data_out_ready) and (not cache_hit); when st_write => if cs = '1' and req_write = '1' then next_state <= st_write; @@ -203,6 +216,37 @@ begin end if; end process; + cache_address_check: process(cache_tag_memory_data_out, cache_line_memory_data_out, address_tag) + begin + if cache_tag_memory_data_out = address_tag then + address_hit <= '1'; + current_byte_valid <= cache_line_memory_data_out(35 downto 32); + else + address_hit <= '0'; + current_byte_valid <= "0000"; + end if; + end process; + + cache_byte_valid_check: process(address_byte, current_byte_valid) + begin + case address_byte is + when "00" => byte_valid_hit <= current_byte_valid(0); + when "01" => byte_valid_hit <= current_byte_valid(1); + when "10" => byte_valid_hit <= current_byte_valid(2); + when "11" => byte_valid_hit <= current_byte_valid(3); + when others => byte_valid_hit <= '0'; + end case; + end process; + + cache_hit_check: process(byte_valid_hit, address_hit, cache_inhibit) + begin + if address_hit = '1' and byte_valid_hit = '1' and cache_inhibit = '0' then + cache_hit <= '1'; + else + cache_hit <= '0'; + end if; + end process; + byte_enable_decode: process(address_byte) begin case address_byte is @@ -214,14 +258,14 @@ begin end case; end process; - data_out_demux: process(address_byte, sdram_data_out_ready, sdram_data_out, current_word) + data_out_demux: process(address_byte, sdram_data_out_ready, sdram_data_out, cache_line_memory_data_out, current_word) begin -- when the SDRAM is presenting data, feed it direct to the CPU. -- otherwise feed data from our cache memory. if sdram_data_out_ready = '1' then current_word <= sdram_data_out; else - current_word <= (others => '0'); + current_word <= cache_line_memory_data_out(31 downto 0); end if; case address_byte is @@ -233,6 +277,51 @@ begin end case; end process; + cache_write: process(current_state, data_in, next_state, write_back, cache_line_memory_data_out, sdram_data_out, sdram_data_out_ready, address_byte, current_byte_valid) + begin + if (next_state = st_read) or (write_back = '1') then + cache_tag_memory_write_enable <= '1'; + else + cache_tag_memory_write_enable <= '0'; + end if; + + cache_line_memory_write_enable <= '0'; + cache_line_memory_data_in <= cache_line_memory_data_out; + + if next_state = st_read then + cache_line_memory_data_in <= (others => '0'); -- set word and all valid flags to 1 + cache_line_memory_write_enable <= '1'; + end if; + + -- has our read completed? + if current_state = st_read then + if sdram_data_out_ready = '1' then + cache_line_memory_data_in <= "1111" & sdram_data_out; + cache_line_memory_write_enable <= '1'; + end if; + elsif write_back = '1' then + case address_byte is + when "00" => + cache_line_memory_data_in <= current_byte_valid(3 downto 1) & "1" & + cache_line_memory_data_out(31 downto 8) & data_in; + when "01" => + cache_line_memory_data_in <= + current_byte_valid(3 downto 2) & "1" & current_byte_valid(0) & + cache_line_memory_data_out(31 downto 16) & data_in & cache_line_memory_data_out(7 downto 0); + when "10" => + cache_line_memory_data_in <= + current_byte_valid(3) & "1" & current_byte_valid(1 downto 0) & + cache_line_memory_data_out(31 downto 24) & data_in & cache_line_memory_data_out(15 downto 0); + when "11" => + cache_line_memory_data_in <= + "1" & current_byte_valid(2 downto 0) & + data_in & cache_line_memory_data_out(23 downto 0); + when others => -- shut up, compiler! + end case; + cache_line_memory_write_enable <= '1'; + end if; + end process; + sdram_registers: process(clk) begin if rising_edge(clk) then @@ -279,4 +368,24 @@ begin SDRAM_DATA => SDRAM_DQ ); -end; + -- block RAM used to store cache line data and byte validity (packs nicely into 36 bits) + cacheline_memory_sram: entity work.RAM4K36 + port map ( + clk => clk, + write => cache_line_memory_write_enable, + address => address_line, + data_in => cache_line_memory_data_in, + data_out => cache_line_memory_data_out + + ); + + -- block RAM used to store cache line tag memory (packs nicely into 9 bits) + cachetag_memory_sram: entity work.RAM4K9 + port map ( + clock => clk, + wren => cache_tag_memory_write_enable, + address => address_line, + data => cache_tag_memory_data_in, + q => cache_tag_memory_data_out + ); + end; diff --git a/vhdl/MonZ80_template.vhd b/vhdl/MonZ80_template.vhd deleted file mode 100644 index c34c850..0000000 --- a/vhdl/MonZ80_template.vhd +++ /dev/null @@ -1,56 +0,0 @@ ---+-----------------------------------+-------------------------------------+-- ---| ___ ___ | (c) 2013-2014 William R Sowerbutts |-- ---| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |-- ---| / __|/ _ \ / __|_ / _ \| | | | | |-- ---| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |-- ---| |___/\___/ \___/___\___/ \___/ | |-- ---| | http://sowerbutts.com/ |-- ---+-----------------------------------+-------------------------------------+-- ---| An inferrable 4KB ROM to contain the monitor program |-- ---+-------------------------------------------------------------------------+-- --- --- MonZ80_template.vhd contains the template VHDL for the ROM but no actual --- data. The "ROMHERE" string is replaced by byte data by the "make_vhdl_rom" --- tool in software/tools which is invoked to generate "MonZ80.vhd" after --- the monitor program has been assembled. - -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -entity MonZ80 is - port( - clk : in std_logic; - a : in std_logic_vector(11 downto 0); - d : out std_logic_vector(7 downto 0) - ); -end MonZ80; - -architecture arch of MonZ80 is - constant byte_rom_WIDTH: integer := 8; - type byte_rom_type is array (0 to 4095) of std_logic_vector(byte_rom_WIDTH-1 downto 0); - signal address_latch : std_logic_vector(11 downto 0) := (others => '0'); - - -- actually memory cells - signal byte_rom : byte_rom_type := ( - -- ROM contents follows - - -%ROMHERE% - - - ); - -begin - - ram_process: process(clk, byte_rom) - begin - if rising_edge(clk) then - -- latch the address, in order to infer a synchronous memory - address_latch <= a; - end if; - end process; - - d <= byte_rom(to_integer(unsigned(address_latch))); - -end arch; diff --git a/vhdl/RAM4K36.vhd b/vhdl/RAM4K36.vhd new file mode 100644 index 0000000..0db864f --- /dev/null +++ b/vhdl/RAM4K36.vhd @@ -0,0 +1,67 @@ +--+-----------------------------------+-------------------------------------+-- +--| ___ ___ | (c) 2013-2014 William R Sowerbutts |-- +--| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |-- +--| / __|/ _ \ / __|_ / _ \| | | | | |-- +--| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |-- +--| |___/\___/ \___/___\___/ \___/ | |-- +--| | http://sowerbutts.com/ |-- +--+-----------------------------------+-------------------------------------+-- +--| A 4096 entry deep, 36-bit wide RAM using four RAM4K9 devices (and thus |-- +--| eight Xilinx RAMB16BWER devices) |-- +--+-------------------------------------------------------------------------+-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +library UNISIM; +entity RAM4K36 is + port( + clk : in std_logic; + write : in std_logic; + address : in std_logic_vector(11 downto 0); + data_in : in std_logic_vector(35 downto 0); + data_out : out std_logic_vector(35 downto 0) + ); +end RAM4K36; + +architecture behaviour of RAM4K36 is + +begin + + ram0: entity work.RAM4K9 + port map ( + clock => clk, + wren => write, + address => address, + data => data_in(8 downto 0), + q => data_out(8 downto 0) + ); + + ram1: entity work.RAM4K9 + port map ( + clock => clk, + wren => write, + address => address, + data => data_in(17 downto 9), + q => data_out(17 downto 9) + ); + + ram2: entity work.RAM4K9 + port map ( + clock => clk, + wren => write, + address => address, + data => data_in(26 downto 18), + q => data_out(26 downto 18) + ); + + ram3: entity work.RAM4K9 + port map ( + clock => clk, + wren => write, + address => address, + data => data_in(35 downto 27), + q => data_out(35 downto 27) + ); + +end; diff --git a/vhdl/RAM4K9.vhd b/vhdl/RAM4K9.vhd new file mode 100644 index 0000000..ac5a065 --- /dev/null +++ b/vhdl/RAM4K9.vhd @@ -0,0 +1,184 @@ +-- megafunction wizard: %RAM: 1-PORT% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altsyncram + +-- ============================================================ +-- File Name: ram4k9.vhd +-- Megafunction Name(s): +-- altsyncram +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 11.0 Build 208 07/03/2011 SP 1 SJ Full Version +-- ************************************************************ + + +--Copyright (C) 1991-2011 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY ram4k9 IS + PORT + ( + address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); + clock : IN STD_LOGIC := '1'; + data : IN STD_LOGIC_VECTOR (8 DOWNTO 0); + wren : IN STD_LOGIC ; + q : OUT STD_LOGIC_VECTOR (8 DOWNTO 0) + ); +END ram4k9; + + +ARCHITECTURE SYN OF ram4k9 IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (8 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + clock_enable_input_a : STRING; + clock_enable_output_a : STRING; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_reg_a : STRING; + power_up_uninitialized : STRING; + ram_block_type : STRING; + widthad_a : NATURAL; + width_a : NATURAL; + width_byteena_a : NATURAL + ); + PORT ( + address_a : IN STD_LOGIC_VECTOR (11 DOWNTO 0); + clock0 : IN STD_LOGIC ; + data_a : IN STD_LOGIC_VECTOR (8 DOWNTO 0); + wren_a : IN STD_LOGIC ; + q_a : OUT STD_LOGIC_VECTOR (8 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q <= sub_wire0(8 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + clock_enable_input_a => "BYPASS", + clock_enable_output_a => "BYPASS", + intended_device_family => "Cyclone II", + lpm_hint => "ENABLE_RUNTIME_MOD=NO", + lpm_type => "altsyncram", + numwords_a => 4096, + operation_mode => "SINGLE_PORT", + outdata_aclr_a => "NONE", + outdata_reg_a => "UNREGISTERED", + power_up_uninitialized => "FALSE", + ram_block_type => "M4K", + widthad_a => 12, + width_a => 9, + width_byteena_a => 1 + ) + PORT MAP ( + address_a => address, + clock0 => clock, + data_a => data, + wren_a => wren, + q_a => sub_wire0 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" +-- Retrieval info: PRIVATE: AclrAddr NUMERIC "0" +-- Retrieval info: PRIVATE: AclrByte NUMERIC "0" +-- Retrieval info: PRIVATE: AclrData NUMERIC "0" +-- Retrieval info: PRIVATE: AclrOutput NUMERIC "0" +-- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" +-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "9" +-- Retrieval info: PRIVATE: BlankMemory NUMERIC "1" +-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" +-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" +-- Retrieval info: PRIVATE: Clken NUMERIC "0" +-- Retrieval info: PRIVATE: DataBusSeparated NUMERIC "1" +-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" +-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" +-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" +-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +-- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" +-- Retrieval info: PRIVATE: JTAG_ID STRING "NONE" +-- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" +-- Retrieval info: PRIVATE: MIFfilename STRING "" +-- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "4096" +-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2" +-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" +-- Retrieval info: PRIVATE: RegAddr NUMERIC "1" +-- Retrieval info: PRIVATE: RegData NUMERIC "1" +-- Retrieval info: PRIVATE: RegOutput NUMERIC "0" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: SingleClock NUMERIC "1" +-- Retrieval info: PRIVATE: UseDQRAM NUMERIC "1" +-- Retrieval info: PRIVATE: WRCONTROL_ACLR_A NUMERIC "0" +-- Retrieval info: PRIVATE: WidthAddr NUMERIC "12" +-- Retrieval info: PRIVATE: WidthData NUMERIC "9" +-- Retrieval info: PRIVATE: rden NUMERIC "0" +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +-- Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" +-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "4096" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "SINGLE_PORT" +-- Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +-- Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED" +-- Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE" +-- Retrieval info: CONSTANT: RAM_BLOCK_TYPE STRING "M4K" +-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "12" +-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "9" +-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +-- Retrieval info: USED_PORT: address 0 0 12 0 INPUT NODEFVAL "address[11..0]" +-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +-- Retrieval info: USED_PORT: data 0 0 9 0 INPUT NODEFVAL "data[8..0]" +-- Retrieval info: USED_PORT: q 0 0 9 0 OUTPUT NODEFVAL "q[8..0]" +-- Retrieval info: USED_PORT: wren 0 0 0 0 INPUT NODEFVAL "wren" +-- Retrieval info: CONNECT: @address_a 0 0 12 0 address 0 0 12 0 +-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +-- Retrieval info: CONNECT: @data_a 0 0 9 0 data 0 0 9 0 +-- Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0 +-- Retrieval info: CONNECT: q 0 0 9 0 @q_a 0 0 9 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL ram4k9.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL ram4k9.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL ram4k9.cmp TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL ram4k9.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL ram4k9_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf diff --git a/vhdl/T80_Pack.vhd b/vhdl/T80_Pack.vhd index 6904b66..9305475 100644 --- a/vhdl/T80_Pack.vhd +++ b/vhdl/T80_Pack.vhd @@ -59,7 +59,9 @@ library IEEE; use IEEE.std_logic_1164.all; package T80_Pack is - + constant T80_TAG_MEM: std_logic_vector(1 downto 0) := "01"; + constant T80_TAG_IO: std_logic_vector(1 downto 0) := "10"; + component T80 generic( Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB diff --git a/vhdl/DE0_SEG7.vhd b/vhdl/board/de0/DE0_SEG7.vhd similarity index 100% rename from vhdl/DE0_SEG7.vhd rename to vhdl/board/de0/DE0_SEG7.vhd diff --git a/vhdl/SDRAM_Controller.vhd b/vhdl/board/de0/SDRAM_Controller.vhd similarity index 100% rename from vhdl/SDRAM_Controller.vhd rename to vhdl/board/de0/SDRAM_Controller.vhd diff --git a/vhdl/pll.vhd b/vhdl/board/de0/pll_de0.vhd similarity index 100% rename from vhdl/pll.vhd rename to vhdl/board/de0/pll_de0.vhd diff --git a/vhdl/top_level.vhd b/vhdl/board/de0/top_level_de0.vhd similarity index 99% rename from vhdl/top_level.vhd rename to vhdl/board/de0/top_level_de0.vhd index 327c5dc..e3de01b 100644 --- a/vhdl/top_level.vhd +++ b/vhdl/board/de0/top_level_de0.vhd @@ -15,6 +15,7 @@ library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; +use work.T80_Pack.ALL; entity top_level is Port ( diff --git a/vhdl/board/de0_nano/SDRAM_Controller.vhd b/vhdl/board/de0_nano/SDRAM_Controller.vhd new file mode 100644 index 0000000..8669446 --- /dev/null +++ b/vhdl/board/de0_nano/SDRAM_Controller.vhd @@ -0,0 +1,472 @@ +---------------------------------------------------------------------------------- +-- Engineer: Mike Field +-- +-- Create Date: 14:09:12 09/15/2013 +-- Module Name: SDRAM_Controller - Behavioral +-- Description: Simple SDRAM controller for a Micron 48LC16M16A2-7E +-- or Micron 48LC4M16A2-7E @ 100MHz +-- Revision: +-- Revision 0.1 - Initial version +-- Revision 0.2 - Removed second clock signal that isn't needed. +-- Revision 0.3 - Added back-to-back reads and writes. +-- Revision 0.4 - Allow refeshes to be delayed till next PRECHARGE is issued, +-- Unless they get really, really delayed. If a delay occurs multiple +-- refreshes might get pushed out, but it will have avioded about +-- 50% of the refresh overhead +-- Revision 0.5 - Add more paramaters to the design, allowing it to work for both the +-- Papilio Pro and Logi-Pi +-- +-- Worst case performance (single accesses to different rows or banks) is: +-- Writes 16 cycles = 6,250,000 writes/sec = 25.0MB/s (excluding refresh overhead) +-- Reads 17 cycles = 5,882,352 reads/sec = 23.5MB/s (excluding refresh overhead) +-- +-- For 1:1 mixed reads and writes into the same row it is around 88MB/s +-- For reads or wries to the same it is can be as high as 184MB/s +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +library UNISIM; +use IEEE.NUMERIC_STD.ALL; +library altera_mf; +use altera_mf.altera_mf_components.all; + + +entity SDRAM_Controller is + generic ( + sdram_address_width : natural; + sdram_column_bits : natural; + sdram_startup_cycles: natural; + cycles_per_refresh : natural + ); + Port ( clk : in STD_LOGIC; + reset : in STD_LOGIC; + + -- Interface to issue reads or write data + cmd_ready : out STD_LOGIC; -- '1' when a new command will be acted on + cmd_enable : in STD_LOGIC; -- Set to '1' to issue new command (only acted on when cmd_read = '1') + cmd_wr : in STD_LOGIC; -- Is this a write? + cmd_address : in STD_LOGIC_VECTOR(sdram_address_width-2 downto 0); -- address to read/write + cmd_byte_enable : in STD_LOGIC_VECTOR(3 downto 0); -- byte masks for the write command + cmd_data_in : in STD_LOGIC_VECTOR(31 downto 0); -- data for the write command + + data_out : out STD_LOGIC_VECTOR(31 downto 0); -- word read from SDRAM + data_out_ready : out STD_LOGIC; -- is new data ready? + + -- SDRAM signals + SDRAM_CLK : out STD_LOGIC; + SDRAM_CKE : out STD_LOGIC; + SDRAM_CS : out STD_LOGIC; + SDRAM_RAS : out STD_LOGIC; + SDRAM_CAS : out STD_LOGIC; + SDRAM_WE : out STD_LOGIC; + SDRAM_DQM : out STD_LOGIC_VECTOR( 1 downto 0); + SDRAM_ADDR : out STD_LOGIC_VECTOR(12 downto 0); + SDRAM_BA : out STD_LOGIC_VECTOR( 1 downto 0); + SDRAM_DATA : inout STD_LOGIC_VECTOR(15 downto 0)); +end SDRAM_Controller; + +architecture Behavioral of SDRAM_Controller is + -- From page 37 of MT48LC16M16A2 datasheet + -- Name (Function) CS# RAS# CAS# WE# DQM Addr Data + -- COMMAND INHIBIT (NOP) H X X X X X X + -- NO OPERATION (NOP) L H H H X X X + -- ACTIVE L L H H X Bank/row X + -- READ L H L H L/H Bank/col X + -- WRITE L H L L L/H Bank/col Valid + -- BURST TERMINATE L H H L X X Active + -- PRECHARGE L L H L X Code X + -- AUTO REFRESH L L L H X X X + -- LOAD MODE REGISTER L L L L X Op-code X + -- Write enable X X X X L X Active + -- Write inhibit X X X X H X High-Z + + -- Here are the commands mapped to constants + constant CMD_UNSELECTED : std_logic_vector(3 downto 0) := "1000"; + 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_TERMINATE : std_logic_vector(3 downto 0) := "0110"; + constant CMD_PRECHARGE : std_logic_vector(3 downto 0) := "0010"; + constant CMD_REFRESH : std_logic_vector(3 downto 0) := "0001"; + constant CMD_LOAD_MODE_REG : std_logic_vector(3 downto 0) := "0000"; + + constant MODE_REG : std_logic_vector(12 downto 0) := + -- Reserved, wr bust, OpMode, CAS Latency (2), Burst Type, Burst Length (2) + "000" & "0" & "00" & "010" & "0" & "001"; + + signal iob_command : std_logic_vector( 3 downto 0) := CMD_NOP; + signal iob_address : std_logic_vector(12 downto 0) := (others => '0'); + signal iob_data : std_logic_vector(15 downto 0) := (others => '0'); + signal iob_dqm : std_logic_vector( 1 downto 0) := (others => '0'); + signal iob_cke : std_logic := '0'; + signal iob_bank : std_logic_vector( 1 downto 0) := (others => '0'); + + attribute IOB: string; + attribute IOB of iob_command: signal is "true"; + attribute IOB of iob_address: signal is "true"; + attribute IOB of iob_dqm : signal is "true"; + attribute IOB of iob_cke : signal is "true"; + attribute IOB of iob_bank : signal is "true"; + attribute IOB of iob_data : signal is "true"; + + signal iob_data_next : std_logic_vector(15 downto 0) := (others => '0'); + signal captured_data : std_logic_vector(15 downto 0) := (others => '0'); + signal captured_data_last : std_logic_vector(15 downto 0) := (others => '0'); + signal sdram_din : std_logic_vector(15 downto 0); + attribute IOB of captured_data : signal is "true"; + + type fsm_state is (s_startup, + s_idle_in_6, s_idle_in_5, s_idle_in_4, s_idle_in_3, s_idle_in_2, s_idle_in_1, + s_idle, + s_open_in_2, s_open_in_1, + s_write_1, s_write_2, s_write_3, + s_read_1, s_read_2, s_read_3, s_read_4, + s_precharge + ); + + signal state : fsm_state := s_startup; + attribute FSM_ENCODING : string; + attribute FSM_ENCODING of state : signal is "ONE-HOT"; + + -- dual purpose counter, it counts up during the startup phase, then is used to trigger refreshes. + constant startup_refresh_max : unsigned(13 downto 0) := (others => '1'); + signal startup_refresh_count : unsigned(13 downto 0) := startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + + -- logic to decide when to refresh + signal pending_refresh : std_logic := '0'; + signal forcing_refresh : std_logic := '0'; + + -- The incoming address is split into these three values + signal addr_row : std_logic_vector(12 downto 0) := (others => '0'); + signal addr_col : std_logic_vector(12 downto 0) := (others => '0'); + signal addr_bank : std_logic_vector( 1 downto 0) := (others => '0'); + + signal dqm_sr : std_logic_vector( 3 downto 0) := (others => '1'); -- an extra two bits in case CAS=3 + + -- signals to hold the requested transaction before it is completed + signal save_wr : std_logic := '0'; + signal save_row : std_logic_vector(12 downto 0); + signal save_bank : std_logic_vector( 1 downto 0); + signal save_col : std_logic_vector(12 downto 0); + signal save_data_in : std_logic_vector(31 downto 0); + signal save_byte_enable : std_logic_vector( 3 downto 0); + + -- control when new transactions are accepted + signal ready_for_new : std_logic := '0'; + signal got_transaction : std_logic := '0'; + + signal can_back_to_back : std_logic := '0'; + + -- signal to control the Hi-Z state of the DQ bus + signal iob_dq_hiz : std_logic := '1'; + + -- signals for when to read the data off of the bus + signal data_ready_delay : std_logic_vector( 4 downto 0); + + -- bit indexes used when splitting the address into row/colum/bank. + constant start_of_col : natural := 0; + constant end_of_col : natural := sdram_column_bits-2; + constant start_of_bank : natural := sdram_column_bits-1; + constant end_of_bank : natural := sdram_column_bits; + constant start_of_row : natural := sdram_column_bits+1; + constant end_of_row : natural := sdram_address_width-2; + constant prefresh_cmd : natural := 10; +begin + -- Indicate the need to refresh when the counter is 2048, + -- Force a refresh when the counter is 4096 - (if a refresh is forced, + -- multiple refresshes will be forced until the counter is below 2048 + pending_refresh <= startup_refresh_count(11); + forcing_refresh <= startup_refresh_count(12); + + -- tell the outside world when we can accept a new transaction; + cmd_ready <= ready_for_new; + ---------------------------------------------------------------------------- + -- Seperate the address into row / bank / address + ---------------------------------------------------------------------------- + addr_row(end_of_row-start_of_row downto 0) <= cmd_address(end_of_row downto start_of_row); -- 12:0 <= 22:10 + addr_bank <= cmd_address(end_of_bank downto start_of_bank); -- 1:0 <= 9:8 + addr_col(sdram_column_bits-1 downto 0) <= cmd_address(end_of_col downto start_of_col) & '0'; -- 8:0 <= 7:0 & '0' + --addr_row(12 downto 0) <= cmd_address(22 downto 10); -- 12:0 <= 22:10 + --addr_bank <= cmd_address( 9 downto 8); -- 1:0 <= 9:8 + --addr_col(8 downto 0) <= cmd_address( 7 downto 0) & '0'; -- 8:0 <= 7:0 & '0' + + ----------------------------------------------- + --!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + --!! Ensure that all outputs are registered. !! + --!! Check the pinout report to be sure !! + --!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ----------------------------------------------- + sdram_cke <= iob_cke; + sdram_CS <= iob_command(3); + sdram_RAS <= iob_command(2); + sdram_CAS <= iob_command(1); + sdram_WE <= iob_command(0); + sdram_dqm <= iob_dqm; + sdram_ba <= iob_bank; + sdram_addr <= iob_address; + + --------------------------------------------------------------- + -- Explicitly set up the tristate I/O buffers on the DQ signals + --------------------------------------------------------------- +iob_dq_g: for i in 0 to 15 generate + begin +iob_dq_iob: altiobuf_bidir + generic map (number_of_channels => 1) + port map ( dataout(0) => sdram_din(i), dataio(0) => sdram_data(i), datain(0) => iob_data(i), oe(0) => iob_dq_hiz); +end generate; + +capture_proc: process(clk) + begin + if rising_edge(clk) then + captured_data <= sdram_din; + end if; + end process; + +main_proc: process(clk) + begin + if rising_edge(clk) then + captured_data_last <= captured_data; + + ------------------------------------------------ + -- Default state is to do nothing + ------------------------------------------------ + iob_command <= CMD_NOP; + iob_address <= (others => '0'); + iob_bank <= (others => '0'); + + ------------------------------------------------ + -- countdown for initialisation & refresh + ------------------------------------------------ + startup_refresh_count <= startup_refresh_count+1; + + ------------------------------------------------------------------- + -- It we are ready for a new tranasction and one is being presented + -- then accept it. Also remember what we are reading or writing, + -- and if it can be back-to-backed with the last transaction + ------------------------------------------------------------------- + if ready_for_new = '1' and cmd_enable = '1' then + if save_bank = addr_bank and save_row = addr_row then + can_back_to_back <= '1'; + else + can_back_to_back <= '0'; + end if; + save_row <= addr_row; + save_bank <= addr_bank; + save_col <= addr_col; + save_wr <= cmd_wr; + save_data_in <= cmd_data_in; + save_byte_enable <= cmd_byte_enable; + got_transaction <= '1'; + ready_for_new <= '0'; + end if; + + ------------------------------------------------ + -- Handle the data coming back from the + -- SDRAM for the Read transaction + ------------------------------------------------ + data_out_ready <= '0'; + if data_ready_delay(0) = '1' then + data_out <= captured_data & captured_data_last; + data_out_ready <= '1'; + end if; + + ---------------------------------------------------------------------------- + -- update shift registers used to choose when to present data to/from memory + ---------------------------------------------------------------------------- + data_ready_delay <= '0' & data_ready_delay(data_ready_delay'high downto 1); + iob_dqm <= dqm_sr(1 downto 0); + dqm_sr <= "11" & dqm_sr(dqm_sr'high downto 2); + + case state is + when s_startup => + ------------------------------------------------------------------------ + -- This is the initial startup state, where we wait for at least 100us + -- before starting the start sequence + -- + -- The initialisation is sequence is + -- * de-assert SDRAM_CKE + -- * 100us wait, + -- * assert SDRAM_CKE + -- * wait at least one cycle, + -- * PRECHARGE + -- * wait 2 cycles + -- * REFRESH, + -- * tREF wait + -- * REFRESH, + -- * tREF wait + -- * LOAD_MODE_REG + -- * 2 cycles wait + ------------------------------------------------------------------------ + iob_CKE <= '1'; + + -- All the commands during the startup are NOPS, except these + if startup_refresh_count = startup_refresh_max-31 then + -- ensure all rows are closed + iob_command <= CMD_PRECHARGE; + iob_address(prefresh_cmd) <= '1'; -- all banks + iob_bank <= (others => '0'); + elsif startup_refresh_count = startup_refresh_max-23 then + -- these refreshes need to be at least tREF (66ns) apart + iob_command <= CMD_REFRESH; + elsif startup_refresh_count = startup_refresh_max-15 then + iob_command <= CMD_REFRESH; + elsif startup_refresh_count = startup_refresh_max-7 then + -- Now load the mode register + iob_command <= CMD_LOAD_MODE_REG; + iob_address <= MODE_REG; + end if; + + ------------------------------------------------------ + -- if startup is coomplete then go into idle mode, + -- get prepared to accept a new command, and schedule + -- the first refresh cycle + ------------------------------------------------------ + if startup_refresh_count = 0 then + state <= s_idle; + ready_for_new <= '1'; + got_transaction <= '0'; + startup_refresh_count <= to_unsigned(2048 - cycles_per_refresh+1,14); + end if; + + when s_idle_in_6 => state <= s_idle_in_5; + when s_idle_in_5 => state <= s_idle_in_4; + when s_idle_in_4 => state <= s_idle_in_3; + when s_idle_in_3 => state <= s_idle_in_2; + when s_idle_in_2 => state <= s_idle_in_1; + when s_idle_in_1 => state <= s_idle; + + when s_idle => + -- Priority is to issue a refresh if one is outstanding + if pending_refresh = '1' or forcing_refresh = '1' then + ------------------------------------------------------------------------ + -- Start the refresh cycle. + -- This tasks tRFC (66ns), so 6 idle cycles are needed @ 100MHz + ------------------------------------------------------------------------ + state <= s_idle_in_3; + iob_command <= CMD_REFRESH; + startup_refresh_count <= startup_refresh_count - cycles_per_refresh+1; + elsif got_transaction = '1' then + -------------------------------- + -- Start the read or write cycle. + -- First task is to open the row + -------------------------------- + state <= s_open_in_1; + iob_command <= CMD_ACTIVE; + iob_address <= save_row; + iob_bank <= save_bank; + end if; + + -------------------------------------------- + -- Opening the row ready for reads or writes + -------------------------------------------- + when s_open_in_2 => state <= s_open_in_1; + + when s_open_in_1 => + -- still waiting for row to open + if save_wr = '1' then + state <= s_write_1; + iob_dq_hiz <= '0'; + iob_data <= save_data_in(15 downto 0); -- get the DQ bus out of HiZ early + else + iob_dq_hiz <= '1'; + state <= s_read_1; + end if; + -- we will be ready for a new transaction next cycle! + ready_for_new <= '1'; + got_transaction <= '0'; + + ---------------------------------- + -- Processing the read transaction + ---------------------------------- + when s_read_1 => + state <= s_read_2; + iob_command <= CMD_READ; + iob_address <= save_col; + iob_bank <= save_bank; + iob_address(prefresh_cmd) <= '0'; -- A10 actually matters - it selects auto precharge + + -- Schedule reading the data values off the bus + data_ready_delay(data_ready_delay'high) <= '1'; + + -- Set the data masks to read all bytes + iob_dqm <= (others => '0'); + dqm_sr(1 downto 0) <= (others => '0'); + + when s_read_2 => + state <= s_read_3; + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + end if; + end if; + + when s_read_3 => + state <= s_read_4; + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + end if; + end if; + + when s_read_4 => + state <= s_precharge; + -- can we do back-to-back read? + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + else + state <= s_open_in_2; -- we have to wait for the read data to come back before we swutch the bus into HiZ + end if; + end if; + + ------------------------------------------------------------------ + -- Processing the write transaction + ------------------------------------------------------------------- + when s_write_1 => + state <= s_write_2; + iob_command <= CMD_WRITE; + iob_address <= save_col; + iob_address(prefresh_cmd) <= '0'; -- A10 actually matters - it selects auto precharge + iob_bank <= save_bank; + iob_dqm <= NOT save_byte_enable(1 downto 0); + dqm_sr(1 downto 0) <= NOT save_byte_enable(3 downto 2); + iob_data <= save_data_in(15 downto 0); + iob_data_next <= save_data_in(31 downto 16); + + when s_write_2 => + state <= s_write_3; + iob_data <= iob_data_next; + + when s_write_3 => -- must wait tRDL, hence the extra idle state + iob_dq_hiz <= '1'; + state <= s_precharge; + + ------------------------------------------------------------------- + -- Closing the row off (this closes all banks) + ------------------------------------------------------------------- + when s_precharge => + state <= s_idle_in_3; + iob_command <= CMD_PRECHARGE; + iob_address(prefresh_cmd) <= '1'; -- A10 actually matters - it selects all banks or just one + + ------------------------------------------------------------------- + -- We should never get here, but if we do then reset the memory + ------------------------------------------------------------------- + when others => + state <= s_startup; + ready_for_new <= '0'; + startup_refresh_count <= startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + end case; + + if reset = '1' then -- Sync reset + state <= s_startup; + ready_for_new <= '0'; + startup_refresh_count <= startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + end if; + end if; + end process; +end Behavioral; \ No newline at end of file diff --git a/vhdl/board/de0_nano/pll_de0_nano.vhd b/vhdl/board/de0_nano/pll_de0_nano.vhd new file mode 100644 index 0000000..1926e5f --- /dev/null +++ b/vhdl/board/de0_nano/pll_de0_nano.vhd @@ -0,0 +1,429 @@ +-- megafunction wizard: %ALTPLL% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altpll + +-- ============================================================ +-- File Name: pll.vhd +-- Megafunction Name(s): +-- altpll +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.1.0 Build 162 10/23/2013 SJ Web Edition +-- ************************************************************ + + +--Copyright (C) 1991-2013 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY pll IS + PORT + ( + areset : IN STD_LOGIC := '0'; + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + c1 : OUT STD_LOGIC ; + c2 : OUT STD_LOGIC ; + locked : OUT STD_LOGIC + ); +END pll; + + +ARCHITECTURE SYN OF pll IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (4 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC ; + SIGNAL sub_wire2 : STD_LOGIC ; + SIGNAL sub_wire3 : STD_LOGIC ; + SIGNAL sub_wire4 : STD_LOGIC ; + SIGNAL sub_wire5 : STD_LOGIC ; + SIGNAL sub_wire6 : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL sub_wire7_bv : BIT_VECTOR (0 DOWNTO 0); + SIGNAL sub_wire7 : STD_LOGIC_VECTOR (0 DOWNTO 0); + + + + COMPONENT altpll + GENERIC ( + bandwidth_type : STRING; + clk0_divide_by : NATURAL; + clk0_duty_cycle : NATURAL; + clk0_multiply_by : NATURAL; + clk0_phase_shift : STRING; + clk1_divide_by : NATURAL; + clk1_duty_cycle : NATURAL; + clk1_multiply_by : NATURAL; + clk1_phase_shift : STRING; + clk2_divide_by : NATURAL; + clk2_duty_cycle : NATURAL; + clk2_multiply_by : NATURAL; + clk2_phase_shift : STRING; + compensate_clock : STRING; + inclk0_input_frequency : NATURAL; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + operation_mode : STRING; + pll_type : STRING; + port_activeclock : STRING; + port_areset : STRING; + port_clkbad0 : STRING; + port_clkbad1 : STRING; + port_clkloss : STRING; + port_clkswitch : STRING; + port_configupdate : STRING; + port_fbin : STRING; + port_inclk0 : STRING; + port_inclk1 : STRING; + port_locked : STRING; + port_pfdena : STRING; + port_phasecounterselect : STRING; + port_phasedone : STRING; + port_phasestep : STRING; + port_phaseupdown : STRING; + port_pllena : STRING; + port_scanaclr : STRING; + port_scanclk : STRING; + port_scanclkena : STRING; + port_scandata : STRING; + port_scandataout : STRING; + port_scandone : STRING; + port_scanread : STRING; + port_scanwrite : STRING; + port_clk0 : STRING; + port_clk1 : STRING; + port_clk2 : STRING; + port_clk3 : STRING; + port_clk4 : STRING; + port_clk5 : STRING; + port_clkena0 : STRING; + port_clkena1 : STRING; + port_clkena2 : STRING; + port_clkena3 : STRING; + port_clkena4 : STRING; + port_clkena5 : STRING; + port_extclk0 : STRING; + port_extclk1 : STRING; + port_extclk2 : STRING; + port_extclk3 : STRING; + self_reset_on_loss_lock : STRING; + width_clock : NATURAL + ); + PORT ( + areset : IN STD_LOGIC ; + clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0); + inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + locked : OUT STD_LOGIC + ); + END COMPONENT; + +BEGIN + sub_wire7_bv(0 DOWNTO 0) <= "0"; + sub_wire7 <= To_stdlogicvector(sub_wire7_bv); + sub_wire4 <= sub_wire0(2); + sub_wire3 <= sub_wire0(0); + sub_wire1 <= sub_wire0(1); + c1 <= sub_wire1; + locked <= sub_wire2; + c0 <= sub_wire3; + c2 <= sub_wire4; + sub_wire5 <= inclk0; + sub_wire6 <= sub_wire7(0 DOWNTO 0) & sub_wire5; + + altpll_component : altpll + GENERIC MAP ( + bandwidth_type => "AUTO", + clk0_divide_by => 1, + clk0_duty_cycle => 50, + clk0_multiply_by => 1, + clk0_phase_shift => "-3000", + clk1_divide_by => 1, + clk1_duty_cycle => 50, + clk1_multiply_by => 1, + clk1_phase_shift => "0", + clk2_divide_by => 1, + clk2_duty_cycle => 50, + clk2_multiply_by => 2, + clk2_phase_shift => "0", + compensate_clock => "CLK1", + inclk0_input_frequency => 20000, + intended_device_family => "Cyclone IV E", + lpm_hint => "CBX_MODULE_PREFIX=pll", + lpm_type => "altpll", + operation_mode => "NORMAL", + pll_type => "AUTO", + port_activeclock => "PORT_UNUSED", + port_areset => "PORT_USED", + port_clkbad0 => "PORT_UNUSED", + port_clkbad1 => "PORT_UNUSED", + port_clkloss => "PORT_UNUSED", + port_clkswitch => "PORT_UNUSED", + port_configupdate => "PORT_UNUSED", + port_fbin => "PORT_UNUSED", + port_inclk0 => "PORT_USED", + port_inclk1 => "PORT_UNUSED", + port_locked => "PORT_USED", + port_pfdena => "PORT_UNUSED", + port_phasecounterselect => "PORT_UNUSED", + port_phasedone => "PORT_UNUSED", + port_phasestep => "PORT_UNUSED", + port_phaseupdown => "PORT_UNUSED", + port_pllena => "PORT_UNUSED", + port_scanaclr => "PORT_UNUSED", + port_scanclk => "PORT_UNUSED", + port_scanclkena => "PORT_UNUSED", + port_scandata => "PORT_UNUSED", + port_scandataout => "PORT_UNUSED", + port_scandone => "PORT_UNUSED", + port_scanread => "PORT_UNUSED", + port_scanwrite => "PORT_UNUSED", + port_clk0 => "PORT_USED", + port_clk1 => "PORT_USED", + port_clk2 => "PORT_USED", + port_clk3 => "PORT_UNUSED", + port_clk4 => "PORT_UNUSED", + port_clk5 => "PORT_UNUSED", + port_clkena0 => "PORT_UNUSED", + port_clkena1 => "PORT_UNUSED", + port_clkena2 => "PORT_UNUSED", + port_clkena3 => "PORT_UNUSED", + port_clkena4 => "PORT_UNUSED", + port_clkena5 => "PORT_UNUSED", + port_extclk0 => "PORT_UNUSED", + port_extclk1 => "PORT_UNUSED", + port_extclk2 => "PORT_UNUSED", + port_extclk3 => "PORT_UNUSED", + self_reset_on_loss_lock => "OFF", + width_clock => 5 + ) + PORT MAP ( + areset => areset, + inclk => sub_wire6, + clk => sub_wire0, + locked => sub_wire2 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c1" +-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" +-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1" +-- Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "1" +-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "100.000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "100.000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "100.000000" +-- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +-- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +-- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +-- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "50.000" +-- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps" +-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0" +-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "2" +-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "2" +-- Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "2" +-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "90.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "100.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "100.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "-54.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps" +-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +-- Retrieval info: PRIVATE: SPREAD_USE STRING "0" +-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +-- Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +-- Retrieval info: PRIVATE: STICKY_CLK2 STRING "1" +-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: USE_CLK0 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK1 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK2 STRING "1" +-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA2 STRING "0" +-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "-1500" +-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK1" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +-- Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +-- Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +-- Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" +-- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +-- Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +-- Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2" +-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +-- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +-- Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +-- Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2 +-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf +-- Retrieval info: CBX_MODULE_PREFIX: ON \ No newline at end of file diff --git a/vhdl/board/de0_nano/top_level_de0_nano.vhd b/vhdl/board/de0_nano/top_level_de0_nano.vhd new file mode 100644 index 0000000..7c71da8 --- /dev/null +++ b/vhdl/board/de0_nano/top_level_de0_nano.vhd @@ -0,0 +1,465 @@ +--+-----------------------------------+-------------------------------------+-- +--| ___ ___ | (c) 2013-2014 William R Sowerbutts |-- +--| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |-- +--| / __|/ _ \ / __|_ / _ \| | | | | |-- +--| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |-- +--| |___/\___/ \___/___\___/ \___/ | |-- +--| | http://sowerbutts.com/ |-- +--+-----------------------------------+-------------------------------------+-- +--| Top level module: connects modules to each other and the outside world |-- +--+-------------------------------------------------------------------------+-- +-- +-- See README.txt for more details +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity top_level is + Port ( sysclk_32m : in std_logic; + sys_clk_pad_i : in std_logic; + rst_n_pad_i : in std_logic; + leds : out std_logic_vector(4 downto 0); + reset_button : in std_logic; + console_select : in std_logic; + + -- UART0 (to FTDI USB chip, no flow control) + serial_rx : in std_logic; + serial_tx : out std_logic; + + -- UART0 (to MAX3232 level shifter chip, hardware flow control) + uart1_rx : in std_logic; + uart1_cts : in std_logic; + uart1_tx : out std_logic; + uart1_rts : out std_logic; + + -- SPI flash chip + flash_spi_cs : out std_logic; + flash_spi_clk : out std_logic; + flash_spi_mosi : out std_logic; + flash_spi_miso : in std_logic; + + -- SD card socket + sdcard_spi_cs : out std_logic; + sdcard_spi_clk : out std_logic; + sdcard_spi_mosi : out std_logic; + sdcard_spi_miso : in std_logic; + + -- SDRAM chip + SDRAM_CLK : out std_logic; + SDRAM_CKE : out std_logic; + SDRAM_CS : out std_logic; + SDRAM_nRAS : out std_logic; + SDRAM_nCAS : out std_logic; + SDRAM_nWE : out std_logic; + SDRAM_DQM : out std_logic_vector( 1 downto 0); + SDRAM_ADDR : out std_logic_vector (12 downto 0); + SDRAM_BA : out std_logic_vector( 1 downto 0); + SDRAM_DQ : inout std_logic_vector (15 downto 0) + ); +end top_level; + +architecture Behavioral of top_level is + constant clk_freq_mhz : natural := 50; -- this is the frequency which the PLL outputs, in MHz. + + -- SDRAM configuration + constant sdram_address_width : natural := 24; + constant sdram_column_bits : natural := 9; + constant cycles_per_refresh : natural := (64000*clk_freq_mhz)/8192-1; + + -- For simulation, we don't need a long init stage. but for real DRAM we need approx 101us. + -- The constant below has a different value when interpreted by the synthesis and simulator + -- tools in order to achieve the desired timing in each. + constant sdram_startup_cycles: natural := 101 * clk_freq_mhz + -- pragma translate_off + - 10000 -- reduce the value the simulator uses + -- pragma translate_on + ; + + -- signals for clocking + signal clk_feedback : std_logic; -- PLL clock feedback + signal clk_unbuffered : std_logic; -- unbuffered system clock + signal clk : std_logic; -- buffered system clock (all logic should be clocked by this) + + -- console latch + signal console_select_clk1 : std_logic; + signal console_select_sync : std_logic; + signal swap_uart01 : std_logic := '0'; + + -- system reset signals + signal power_on_reset : std_logic_vector(1 downto 0) := (others => '1'); + signal system_reset : std_logic; + signal reset_button_clk1 : std_logic; + signal reset_button_sync : std_logic; -- reset button signal, synchronised to our clock + signal reset_request_uart : std_logic; -- reset request signal from FTDI UART (when you send "!~!~!~" to the UART, this line is asserted) + + -- CPU control + signal coldboot : std_logic; + signal cpu_clk_enable : std_logic; + signal cpu_m1_cycle : std_logic; + signal cpu_req_mem : std_logic; + signal cpu_req_io : std_logic; + signal req_mem : std_logic; + signal req_io : std_logic; + signal req_read : std_logic; + signal req_write : std_logic; + signal virtual_address : std_logic_vector(15 downto 0); + signal physical_address : std_logic_vector(25 downto 0); + signal mem_wait : std_logic; + signal cpu_wait : std_logic; + signal dram_wait : std_logic; + signal mmu_wait : std_logic; + signal spimaster0_wait : std_logic; + signal spimaster1_wait : std_logic; + + -- chip selects + signal mmu_cs : std_logic; + signal rom_cs : std_logic; + signal sram_cs : std_logic; + signal dram_cs : std_logic; + signal uartA_cs : std_logic; + signal uartB_cs : std_logic; + signal uart0_cs : std_logic; + signal uart1_cs : std_logic; + signal timer_cs : std_logic; + signal spimaster0_cs : std_logic; + signal spimaster1_cs : std_logic; + signal clkscale_cs : std_logic; + signal gpio_cs : std_logic; + + -- data bus + signal cpu_data_in : std_logic_vector(7 downto 0); + signal cpu_data_out : std_logic_vector(7 downto 0); + signal rom_data_out : std_logic_vector(7 downto 0); + signal sram_data_out : std_logic_vector(7 downto 0); + signal dram_data_out : std_logic_vector(7 downto 0); + signal uart0_data_out : std_logic_vector(7 downto 0); + signal uart1_data_out : std_logic_vector(7 downto 0); + signal timer_data_out : std_logic_vector(7 downto 0); + signal spimaster0_data_out : std_logic_vector(7 downto 0); + signal spimaster1_data_out : std_logic_vector(7 downto 0); + signal mmu_data_out : std_logic_vector(7 downto 0); + signal clkscale_out : std_logic_vector(7 downto 0); + signal gpio_data_out : std_logic_vector(7 downto 0); + + -- GPIO + signal gpio_input : std_logic_vector(7 downto 0); + signal gpio_output : std_logic_vector(7 downto 0); + + -- Interrupts + signal cpu_interrupt_in : std_logic; + signal timer_interrupt : std_logic; + signal uart0_interrupt : std_logic; + signal uart1_interrupt : std_logic; + +begin + -- Hold CPU reset high for 8 clock cycles on startup, + -- and when the user presses their reset button. + process(clk) + begin + if rising_edge(clk) then + -- Xilinx advises using two flip-flops are used to bring external + -- signals which feed control logic into our clock domain. + reset_button_clk1 <= reset_button; + reset_button_sync <= reset_button_clk1; + console_select_clk1 <= console_select; + console_select_sync <= console_select_clk1; + + -- reset the system when requested + if (power_on_reset(0) = '1') then + system_reset <= '1'; + else + system_reset <= '0'; + end if; + + -- shift 0s into the power_on_reset shift register from the MSB + power_on_reset <= '0' & power_on_reset(power_on_reset'length-1 downto 1); + + -- During reset, latch the console select jumper. This is used to + -- optionally swap over the UART roles and move the system console to + -- the second serial port on the IO board. + if system_reset = '1' then + swap_uart01 <= console_select_sync; + else + swap_uart01 <= swap_uart01; + end if; + end if; + end process; + + -- GPIO input signal routing + gpio_input <= coldboot & swap_uart01 & "000000"; + + -- GPIO output signal routing + leds(0) <= gpio_output(0); + leds(1) <= gpio_output(1); + leds(2) <= gpio_output(2); + leds(3) <= gpio_output(3); + + -- User LED (LED1) on Papilio Pro indicates when the CPU is being asked to wait (eg by the SDRAM cache) + leds(4) <= cpu_wait; + + -- Interrupt signal for the CPU + cpu_interrupt_in <= (timer_interrupt or uart0_interrupt or uart1_interrupt); + + -- Z80 CPU core + cpu: entity work.Z80cpu + port map ( + reset => system_reset, + clk => clk, + clk_enable => cpu_clk_enable, + m1_cycle => cpu_m1_cycle, + interrupt => cpu_interrupt_in, + nmi => '0', + req_mem => cpu_req_mem, + req_io => cpu_req_io, + req_read => req_read, + req_write => req_write, + mem_wait => cpu_wait, + address => virtual_address, + data_in => cpu_data_in, + data_out => cpu_data_out + ); + + -- Memory management unit + mmu: entity work.MMU + port map ( + reset => system_reset, + clk => clk, + address_in => virtual_address, + address_out => physical_address, + cpu_data_in => cpu_data_out, + cpu_data_out => mmu_data_out, + req_mem_in => cpu_req_mem, + req_io_in => cpu_req_io, + req_mem_out => req_mem, + req_io_out => req_io, + req_read => req_read, + req_write => req_write, + io_cs => mmu_cs, + cpu_wait => mmu_wait, + access_violated => open -- for now!! + ); + + -- This process determines which IO or memory device the CPU is addressing + -- and asserts the appropriate chip select signals. + cs_process: process(req_mem, req_io, physical_address, virtual_address, uartA_cs, uartB_cs, swap_uart01) + begin + -- memory chip selects: default to unselected + rom_cs <= '0'; + sram_cs <= '0'; + dram_cs <= '0'; + + -- io chip selects: default to unselected + uartA_cs <= '0'; + uartB_cs <= '0'; + mmu_cs <= '0'; + timer_cs <= '0'; + spimaster0_cs <= '0'; + spimaster1_cs <= '0'; + clkscale_cs <= '0'; + gpio_cs <= '0'; + + -- memory address decoding + -- address space is organised as: + -- 0x0 000 000 - 0x0 FFF FFF 16MB DRAM (cached) (mapped to 8MB DRAM twice) + -- 0x1 000 000 - 0x1 FFF FFF 16MB DRAM (uncached) (mapped to 8MB DRAM twice) + -- 0x2 000 000 - 0x2 000 FFF 4KB monitor ROM (FPGA block RAM) + -- 0x2 001 000 - 0x2 001 FFF 4KB SRAM (FPGA block RAM) + -- 0x2 002 000 - 0x3 FFF FFF unused space for future expansion + if physical_address(25) = '0' then + -- bottom 32MB: DRAM handles this + dram_cs <= req_mem; + else + -- top 32MB: other memory devices + case physical_address(24 downto 12) is + when "0000000000000" => rom_cs <= req_mem; + when "0000000000001" => sram_cs <= req_mem; + when others => -- undecoded memory space + end case; + end if; + + -- IO address decoding + case virtual_address(7 downto 3) is + when "00000" => uartA_cs <= req_io; -- 00 ... 07 + when "00010" => timer_cs <= req_io; -- 10 ... 17 + when "00011" => spimaster0_cs <= req_io; -- 18 ... 1F + when "00100" => gpio_cs <= req_io; -- 20 ... 27 + when "00101" => uartB_cs <= req_io; -- 28 ... 2F + when "00110" => spimaster1_cs <= req_io; -- 30 ... 37 + -- unused ports + when "11110" => clkscale_cs <= req_io; -- F0 ... F7 + when "11111" => mmu_cs <= req_io; -- F8 ... FF + when others => + end case; + + -- send the UART chip select to the appropriate UART depending + -- on whether they have been swapped over or not. + if swap_uart01 = '0' then + uart0_cs <= uartB_cs; + uart1_cs <= uartA_cs; + else + uart0_cs <= uartA_cs; + uart1_cs <= uartB_cs; + end if; + end process; + + -- the selected memory device can request the CPU to wait + mem_wait <= + dram_wait when dram_cs='1' else + spimaster0_wait when spimaster0_cs='1' else + spimaster1_wait when spimaster1_cs='1' else + '0'; + + -- the MMU can, at any time, request the CPU wait (this is used when + -- translating IO to memory requests, to implement a wait state for + -- the "17th page") + cpu_wait <= (mem_wait or mmu_wait); + + -- input mux for CPU data bus + cpu_data_in <= + rom_data_out when rom_cs='1' else + dram_data_out when dram_cs='1' else + sram_data_out when sram_cs='1' else + uart0_data_out when uart0_cs='1' else + uart1_data_out when uart1_cs='1' else + timer_data_out when timer_cs='1' else + mmu_data_out when mmu_cs='1' else + spimaster0_data_out when spimaster0_cs='1' else + spimaster1_data_out when spimaster1_cs='1' else + clkscale_out when clkscale_cs='1' else + gpio_data_out when gpio_cs='1' else + rom_data_out; -- default case + + dram: entity work.DRAM + generic map( + sdram_address_width => sdram_address_width, + sdram_column_bits => sdram_column_bits, + sdram_startup_cycles=> sdram_startup_cycles, + cycles_per_refresh => cycles_per_refresh + ) + port map( + clk => clk, + reset => '0', -- important to note that we DO NOT reset the SDRAM controller on reset (it would stop refreshing, which would be bad) + + -- interface to synthetic CPU + cs => dram_cs, + req_read => req_read, + req_write => req_write, + mem_address => physical_address(24 downto 0), + mem_wait => dram_wait, + data_in => cpu_data_out, + data_out => dram_data_out, + coldboot => coldboot, + + -- interface to hardware SDRAM chip + SDRAM_CLK => open, + SDRAM_CKE => SDRAM_CKE, + SDRAM_CS => SDRAM_CS, + SDRAM_nRAS => SDRAM_nRAS, + SDRAM_nCAS => SDRAM_nCAS, + SDRAM_nWE => SDRAM_nWE, + SDRAM_DQM => SDRAM_DQM, + SDRAM_BA => SDRAM_BA, + SDRAM_ADDR => SDRAM_ADDR, + SDRAM_DQ => SDRAM_DQ + ); + + -- 4KB system ROM implemented in block RAM + rom: entity work.MonZ80 + port map( + clk => clk, + A => physical_address(11 downto 0), + D => rom_data_out + ); + + -- 4KB SRAM memory implemented in block RAM + sram: entity work.SSRAM + generic map( + AddrWidth => 12 + ) + port map( + clk => clk, + ce => sram_cs, + we => req_write, + A => physical_address(11 downto 0), + DIn => cpu_data_out, + DOut => sram_data_out + ); + + -- UART connected to FTDI USB UART + uart0: entity work.uart_interface + generic map ( watch_for_reset => 1, clk_frequency => (clk_freq_mhz * 1000000) ) + port map( + clk => clk, + reset => system_reset, + reset_out => reset_request_uart, -- result of watching for reset sequence on the input + serial_in => serial_rx, + serial_out => serial_tx, + serial_rts => open, + serial_cts => '0', + cpu_address => virtual_address(2 downto 0), + cpu_data_in => cpu_data_out, + cpu_data_out => uart0_data_out, + enable => uart0_cs, + interrupt => uart0_interrupt, + req_read => req_read, + req_write => req_write + ); + + -- Timer device (internally scales the clock to 1MHz) + timer: entity work.timer + generic map ( clk_frequency => (clk_freq_mhz * 1000000) ) + port map( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => timer_data_out, + enable => timer_cs, + req_read => req_read, + req_write => req_write, + interrupt => timer_interrupt + ); + + -- GPIO to FPGA pins and/or internal signals + gpio: entity work.gpio + port map( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => gpio_data_out, + enable => gpio_cs, + read_notwrite => req_read, + input_pins => gpio_input, + output_pins => gpio_output + ); + + -- An attempt to allow the CPU clock to be scaled back to run + -- at slower speeds without affecting the clock signal sent to + -- IO devices. Basically this was an attempt to make CP/M games + -- playable :) Very limited success. Might be simpler to remove + -- this entirely. + clkscale: entity work.clkscale + port map ( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => clkscale_out, + enable => clkscale_cs, + read_notwrite => req_read, + clk_enable => cpu_clk_enable + ); + + pll: entity work.pll + port map ( + areset => open, + inclk0 => sys_clk_pad_i, + c0 => sdram_clk, -- 100 Mhz - 180 deg + c1 => clk, -- 100 Mhz + locked => open + ); + +end Behavioral; \ No newline at end of file diff --git a/vhdl/board/de2/SDRAM_Controller.vhd b/vhdl/board/de2/SDRAM_Controller.vhd new file mode 100644 index 0000000..6557ab0 --- /dev/null +++ b/vhdl/board/de2/SDRAM_Controller.vhd @@ -0,0 +1,474 @@ +---------------------------------------------------------------------------------- +-- Engineer: Mike Field +-- +-- Create Date: 14:09:12 09/15/2013 +-- Module Name: SDRAM_Controller - Behavioral +-- Description: Simple SDRAM controller for a Micron 48LC16M16A2-7E +-- or Micron 48LC4M16A2-7E @ 100MHz +-- Revision: +-- Revision 0.1 - Initial version +-- Revision 0.2 - Removed second clock signal that isn't needed. +-- Revision 0.3 - Added back-to-back reads and writes. +-- Revision 0.4 - Allow refeshes to be delayed till next PRECHARGE is issued, +-- Unless they get really, really delayed. If a delay occurs multiple +-- refreshes might get pushed out, but it will have avioded about +-- 50% of the refresh overhead +-- Revision 0.5 - Add more paramaters to the design, allowing it to work for both the +-- Papilio Pro and Logi-Pi +-- +-- Worst case performance (single accesses to different rows or banks) is: +-- Writes 16 cycles = 6,250,000 writes/sec = 25.0MB/s (excluding refresh overhead) +-- Reads 17 cycles = 5,882,352 reads/sec = 23.5MB/s (excluding refresh overhead) +-- +-- For 1:1 mixed reads and writes into the same row it is around 88MB/s +-- For reads or wries to the same it is can be as high as 184MB/s +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +library UNISIM; +use IEEE.NUMERIC_STD.ALL; +library altera_mf; +use altera_mf.altera_mf_components.all; + + +entity SDRAM_Controller is + generic ( + sdram_address_width : natural; + sdram_column_bits : natural; + sdram_startup_cycles: natural; + cycles_per_refresh : natural + ); + Port ( clk : in STD_LOGIC; + reset : in STD_LOGIC; + + -- Interface to issue reads or write data + cmd_ready : out STD_LOGIC; -- '1' when a new command will be acted on + cmd_enable : in STD_LOGIC; -- Set to '1' to issue new command (only acted on when cmd_read = '1') + cmd_wr : in STD_LOGIC; -- Is this a write? + cmd_address : in STD_LOGIC_VECTOR(sdram_address_width-2 downto 0); -- address to read/write + cmd_byte_enable : in STD_LOGIC_VECTOR(3 downto 0); -- byte masks for the write command + cmd_data_in : in STD_LOGIC_VECTOR(31 downto 0); -- data for the write command + + data_out : out STD_LOGIC_VECTOR(31 downto 0); -- word read from SDRAM + data_out_ready : out STD_LOGIC; -- is new data ready? + + -- SDRAM signals + SDRAM_CLK : out STD_LOGIC; + SDRAM_CKE : out STD_LOGIC; + SDRAM_CS : out STD_LOGIC; + SDRAM_RAS : out STD_LOGIC; + SDRAM_CAS : out STD_LOGIC; + SDRAM_WE : out STD_LOGIC; + SDRAM_DQM : out STD_LOGIC_VECTOR( 1 downto 0); + SDRAM_ADDR : out STD_LOGIC_VECTOR(12 downto 0); + SDRAM_BA : out STD_LOGIC_VECTOR( 1 downto 0); + SDRAM_DATA : inout STD_LOGIC_VECTOR(15 downto 0)); +end SDRAM_Controller; + +architecture Behavioral of SDRAM_Controller is + -- From page 37 of MT48LC16M16A2 datasheet + -- Name (Function) CS# RAS# CAS# WE# DQM Addr Data + -- COMMAND INHIBIT (NOP) H X X X X X X + -- NO OPERATION (NOP) L H H H X X X + -- ACTIVE L L H H X Bank/row X + -- READ L H L H L/H Bank/col X + -- WRITE L H L L L/H Bank/col Valid + -- BURST TERMINATE L H H L X X Active + -- PRECHARGE L L H L X Code X + -- AUTO REFRESH L L L H X X X + -- LOAD MODE REGISTER L L L L X Op-code X + -- Write enable X X X X L X Active + -- Write inhibit X X X X H X High-Z + + -- Here are the commands mapped to constants + constant CMD_UNSELECTED : std_logic_vector(3 downto 0) := "1000"; + 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_TERMINATE : std_logic_vector(3 downto 0) := "0110"; + constant CMD_PRECHARGE : std_logic_vector(3 downto 0) := "0010"; + constant CMD_REFRESH : std_logic_vector(3 downto 0) := "0001"; + constant CMD_LOAD_MODE_REG : std_logic_vector(3 downto 0) := "0000"; + + constant MODE_REG : std_logic_vector(12 downto 0) := + -- Reserved, wr bust, OpMode, CAS Latency (2), Burst Type, Burst Length (2) + "000" & "0" & "00" & "010" & "0" & "001"; + + signal iob_command : std_logic_vector( 3 downto 0) := CMD_NOP; + signal iob_address : std_logic_vector(12 downto 0) := (others => '0'); + signal iob_data : std_logic_vector(15 downto 0) := (others => '0'); + signal iob_dqm : std_logic_vector( 1 downto 0) := (others => '0'); + signal iob_cke : std_logic := '0'; + signal iob_bank : std_logic_vector( 1 downto 0) := (others => '0'); + + attribute IOB: string; + attribute IOB of iob_command: signal is "true"; + attribute IOB of iob_address: signal is "true"; + attribute IOB of iob_dqm : signal is "true"; + attribute IOB of iob_cke : signal is "true"; + attribute IOB of iob_bank : signal is "true"; + attribute IOB of iob_data : signal is "true"; + + signal iob_data_next : std_logic_vector(15 downto 0) := (others => '0'); + signal captured_data : std_logic_vector(15 downto 0) := (others => '0'); + signal captured_data_last : std_logic_vector(15 downto 0) := (others => '0'); + signal sdram_din : std_logic_vector(15 downto 0); + attribute IOB of captured_data : signal is "true"; + + type fsm_state is (s_startup, + s_idle_in_6, s_idle_in_5, s_idle_in_4, s_idle_in_3, s_idle_in_2, s_idle_in_1, + s_idle, + s_open_in_2, s_open_in_1, + s_write_1, s_write_2, s_write_3, + s_read_1, s_read_2, s_read_3, s_read_4, + s_precharge + ); + + signal state : fsm_state := s_startup; + attribute FSM_ENCODING : string; + attribute FSM_ENCODING of state : signal is "ONE-HOT"; + + -- dual purpose counter, it counts up during the startup phase, then is used to trigger refreshes. + constant startup_refresh_max : unsigned(13 downto 0) := (others => '1'); + signal startup_refresh_count : unsigned(13 downto 0) := startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + + -- logic to decide when to refresh + signal pending_refresh : std_logic := '0'; + signal forcing_refresh : std_logic := '0'; + + -- The incoming address is split into these three values + signal addr_row : std_logic_vector(12 downto 0) := (others => '0'); + signal addr_col : std_logic_vector(12 downto 0) := (others => '0'); + signal addr_bank : std_logic_vector( 1 downto 0) := (others => '0'); + + signal dqm_sr : std_logic_vector( 3 downto 0) := (others => '1'); -- an extra two bits in case CAS=3 + + -- signals to hold the requested transaction before it is completed + signal save_wr : std_logic := '0'; + signal save_row : std_logic_vector(12 downto 0); + signal save_bank : std_logic_vector( 1 downto 0); + signal save_col : std_logic_vector(12 downto 0); + signal save_data_in : std_logic_vector(31 downto 0); + signal save_byte_enable : std_logic_vector( 3 downto 0); + + -- control when new transactions are accepted + signal ready_for_new : std_logic := '0'; + signal got_transaction : std_logic := '0'; + + signal can_back_to_back : std_logic := '0'; + + -- signal to control the Hi-Z state of the DQ bus + signal iob_dq_hiz : std_logic := '1'; + + -- signals for when to read the data off of the bus + signal data_ready_delay : std_logic_vector( 4 downto 0); + + -- bit indexes used when splitting the address into row/colum/bank. + constant start_of_col : natural := 0; + constant end_of_col : natural := sdram_column_bits-2; + constant start_of_bank : natural := sdram_column_bits-1; + constant end_of_bank : natural := sdram_column_bits; + constant start_of_row : natural := sdram_column_bits+1; + constant end_of_row : natural := sdram_address_width-2; + constant prefresh_cmd : natural := 10; +begin + -- Indicate the need to refresh when the counter is 2048, + -- Force a refresh when the counter is 4096 - (if a refresh is forced, + -- multiple refresshes will be forced until the counter is below 2048 + pending_refresh <= startup_refresh_count(11); + forcing_refresh <= startup_refresh_count(12); + + -- tell the outside world when we can accept a new transaction; + cmd_ready <= ready_for_new; + ---------------------------------------------------------------------------- + -- Seperate the address into row / bank / address + ---------------------------------------------------------------------------- + addr_row(end_of_row-start_of_row downto 0) <= cmd_address(end_of_row downto start_of_row); -- 12:0 <= 22:10 + addr_bank <= cmd_address(end_of_bank downto start_of_bank); -- 1:0 <= 9:8 + addr_col(sdram_column_bits-1 downto 0) <= cmd_address(end_of_col downto start_of_col) & '0'; -- 8:0 <= 7:0 & '0' + --addr_row(12 downto 0) <= cmd_address(22 downto 10); -- 12:0 <= 22:10 + --addr_bank <= cmd_address( 9 downto 8); -- 1:0 <= 9:8 + --addr_col(8 downto 0) <= cmd_address( 7 downto 0) & '0'; -- 8:0 <= 7:0 & '0' + + ----------------------------------------------- + --!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + --!! Ensure that all outputs are registered. !! + --!! Check the pinout report to be sure !! + --!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ----------------------------------------------- + sdram_cke <= iob_cke; + sdram_CS <= iob_command(3); + sdram_RAS <= iob_command(2); + sdram_CAS <= iob_command(1); + sdram_WE <= iob_command(0); + sdram_dqm <= iob_dqm; + sdram_ba <= iob_bank; + sdram_addr <= iob_address; + sdram_din <= sdram_data; + sdram_data <= iob_data when iob_dq_hiz = '0' else (others => 'Z'); + + --------------------------------------------------------------- + -- Explicitly set up the tristate I/O buffers on the DQ signals + --------------------------------------------------------------- +--iob_dq_g: for i in 0 to 15 generate +-- begin +--iob_dq_iob: altiobuf_bidir +-- generic map (number_of_channels => 1) +-- port map ( dataout(0) => sdram_din(i), dataio(0) => sdram_data(i), datain(0) => iob_data(i), oe(0) => iob_dq_hiz); +--end generate; + +capture_proc: process(clk) + begin + if rising_edge(clk) then + captured_data <= sdram_din; + end if; + end process; + +main_proc: process(clk) + begin + if rising_edge(clk) then + captured_data_last <= captured_data; + + ------------------------------------------------ + -- Default state is to do nothing + ------------------------------------------------ + iob_command <= CMD_NOP; + iob_address <= (others => '0'); + iob_bank <= (others => '0'); + + ------------------------------------------------ + -- countdown for initialisation & refresh + ------------------------------------------------ + startup_refresh_count <= startup_refresh_count+1; + + ------------------------------------------------------------------- + -- It we are ready for a new tranasction and one is being presented + -- then accept it. Also remember what we are reading or writing, + -- and if it can be back-to-backed with the last transaction + ------------------------------------------------------------------- + if ready_for_new = '1' and cmd_enable = '1' then + if save_bank = addr_bank and save_row = addr_row then + can_back_to_back <= '1'; + else + can_back_to_back <= '0'; + end if; + save_row <= addr_row; + save_bank <= addr_bank; + save_col <= addr_col; + save_wr <= cmd_wr; + save_data_in <= cmd_data_in; + save_byte_enable <= cmd_byte_enable; + got_transaction <= '1'; + ready_for_new <= '0'; + end if; + + ------------------------------------------------ + -- Handle the data coming back from the + -- SDRAM for the Read transaction + ------------------------------------------------ + data_out_ready <= '0'; + if data_ready_delay(0) = '1' then + data_out <= captured_data & captured_data_last; + data_out_ready <= '1'; + end if; + + ---------------------------------------------------------------------------- + -- update shift registers used to choose when to present data to/from memory + ---------------------------------------------------------------------------- + data_ready_delay <= '0' & data_ready_delay(data_ready_delay'high downto 1); + iob_dqm <= dqm_sr(1 downto 0); + dqm_sr <= "11" & dqm_sr(dqm_sr'high downto 2); + + case state is + when s_startup => + ------------------------------------------------------------------------ + -- This is the initial startup state, where we wait for at least 100us + -- before starting the start sequence + -- + -- The initialisation is sequence is + -- * de-assert SDRAM_CKE + -- * 100us wait, + -- * assert SDRAM_CKE + -- * wait at least one cycle, + -- * PRECHARGE + -- * wait 2 cycles + -- * REFRESH, + -- * tREF wait + -- * REFRESH, + -- * tREF wait + -- * LOAD_MODE_REG + -- * 2 cycles wait + ------------------------------------------------------------------------ + iob_CKE <= '1'; + + -- All the commands during the startup are NOPS, except these + if startup_refresh_count = startup_refresh_max-31 then + -- ensure all rows are closed + iob_command <= CMD_PRECHARGE; + iob_address(prefresh_cmd) <= '1'; -- all banks + iob_bank <= (others => '0'); + elsif startup_refresh_count = startup_refresh_max-23 then + -- these refreshes need to be at least tREF (66ns) apart + iob_command <= CMD_REFRESH; + elsif startup_refresh_count = startup_refresh_max-15 then + iob_command <= CMD_REFRESH; + elsif startup_refresh_count = startup_refresh_max-7 then + -- Now load the mode register + iob_command <= CMD_LOAD_MODE_REG; + iob_address <= MODE_REG; + end if; + + ------------------------------------------------------ + -- if startup is coomplete then go into idle mode, + -- get prepared to accept a new command, and schedule + -- the first refresh cycle + ------------------------------------------------------ + if startup_refresh_count = 0 then + state <= s_idle; + ready_for_new <= '1'; + got_transaction <= '0'; + startup_refresh_count <= to_unsigned(2048 - cycles_per_refresh+1,14); + end if; + + when s_idle_in_6 => state <= s_idle_in_5; + when s_idle_in_5 => state <= s_idle_in_4; + when s_idle_in_4 => state <= s_idle_in_3; + when s_idle_in_3 => state <= s_idle_in_2; + when s_idle_in_2 => state <= s_idle_in_1; + when s_idle_in_1 => state <= s_idle; + + when s_idle => + -- Priority is to issue a refresh if one is outstanding + if pending_refresh = '1' or forcing_refresh = '1' then + ------------------------------------------------------------------------ + -- Start the refresh cycle. + -- This tasks tRFC (66ns), so 6 idle cycles are needed @ 100MHz + ------------------------------------------------------------------------ + state <= s_idle_in_3; + iob_command <= CMD_REFRESH; + startup_refresh_count <= startup_refresh_count - cycles_per_refresh+1; + elsif got_transaction = '1' then + -------------------------------- + -- Start the read or write cycle. + -- First task is to open the row + -------------------------------- + state <= s_open_in_1; + iob_command <= CMD_ACTIVE; + iob_address <= save_row; + iob_bank <= save_bank; + end if; + + -------------------------------------------- + -- Opening the row ready for reads or writes + -------------------------------------------- + when s_open_in_2 => state <= s_open_in_1; + + when s_open_in_1 => + -- still waiting for row to open + if save_wr = '1' then + state <= s_write_1; + iob_dq_hiz <= '0'; + iob_data <= save_data_in(15 downto 0); -- get the DQ bus out of HiZ early + else + iob_dq_hiz <= '1'; + state <= s_read_1; + end if; + -- we will be ready for a new transaction next cycle! + ready_for_new <= '1'; + got_transaction <= '0'; + + ---------------------------------- + -- Processing the read transaction + ---------------------------------- + when s_read_1 => + state <= s_read_2; + iob_command <= CMD_READ; + iob_address <= save_col; + iob_bank <= save_bank; + iob_address(prefresh_cmd) <= '0'; -- A10 actually matters - it selects auto precharge + + -- Schedule reading the data values off the bus + data_ready_delay(data_ready_delay'high) <= '1'; + + -- Set the data masks to read all bytes + iob_dqm <= (others => '0'); + dqm_sr(1 downto 0) <= (others => '0'); + + when s_read_2 => + state <= s_read_3; + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + end if; + end if; + + when s_read_3 => + state <= s_read_4; + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + end if; + end if; + + when s_read_4 => + state <= s_precharge; + -- can we do back-to-back read? + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + else + state <= s_open_in_2; -- we have to wait for the read data to come back before we swutch the bus into HiZ + end if; + end if; + + ------------------------------------------------------------------ + -- Processing the write transaction + ------------------------------------------------------------------- + when s_write_1 => + state <= s_write_2; + iob_command <= CMD_WRITE; + iob_address <= save_col; + iob_address(prefresh_cmd) <= '0'; -- A10 actually matters - it selects auto precharge + iob_bank <= save_bank; + iob_dqm <= NOT save_byte_enable(1 downto 0); + dqm_sr(1 downto 0) <= NOT save_byte_enable(3 downto 2); + iob_data <= save_data_in(15 downto 0); + iob_data_next <= save_data_in(31 downto 16); + + when s_write_2 => + state <= s_write_3; + iob_data <= iob_data_next; + + when s_write_3 => -- must wait tRDL, hence the extra idle state + iob_dq_hiz <= '1'; + state <= s_precharge; + + ------------------------------------------------------------------- + -- Closing the row off (this closes all banks) + ------------------------------------------------------------------- + when s_precharge => + state <= s_idle_in_3; + iob_command <= CMD_PRECHARGE; + iob_address(prefresh_cmd) <= '1'; -- A10 actually matters - it selects all banks or just one + + ------------------------------------------------------------------- + -- We should never get here, but if we do then reset the memory + ------------------------------------------------------------------- + when others => + state <= s_startup; + ready_for_new <= '0'; + startup_refresh_count <= startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + end case; + + if reset = '1' then -- Sync reset + state <= s_startup; + ready_for_new <= '0'; + startup_refresh_count <= startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + end if; + end if; + end process; +end Behavioral; diff --git a/vhdl/board/de2/pll_de2.vhd b/vhdl/board/de2/pll_de2.vhd new file mode 100644 index 0000000..c270ca1 --- /dev/null +++ b/vhdl/board/de2/pll_de2.vhd @@ -0,0 +1,429 @@ +-- megafunction wizard: %ALTPLL% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altpll + +-- ============================================================ +-- File Name: pll.vhd +-- Megafunction Name(s): +-- altpll +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.1.0 Build 162 10/23/2013 SJ Web Edition +-- ************************************************************ + + +--Copyright (C) 1991-2013 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY pll IS + PORT + ( + areset : IN STD_LOGIC := '0'; + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + c1 : OUT STD_LOGIC ; + c2 : OUT STD_LOGIC ; + locked : OUT STD_LOGIC + ); +END pll; + + +ARCHITECTURE SYN OF pll IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (4 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC ; + SIGNAL sub_wire2 : STD_LOGIC ; + SIGNAL sub_wire3 : STD_LOGIC ; + SIGNAL sub_wire4 : STD_LOGIC ; + SIGNAL sub_wire5 : STD_LOGIC ; + SIGNAL sub_wire6 : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL sub_wire7_bv : BIT_VECTOR (0 DOWNTO 0); + SIGNAL sub_wire7 : STD_LOGIC_VECTOR (0 DOWNTO 0); + + + + COMPONENT altpll + GENERIC ( + bandwidth_type : STRING; + clk0_divide_by : NATURAL; + clk0_duty_cycle : NATURAL; + clk0_multiply_by : NATURAL; + clk0_phase_shift : STRING; + clk1_divide_by : NATURAL; + clk1_duty_cycle : NATURAL; + clk1_multiply_by : NATURAL; + clk1_phase_shift : STRING; + clk2_divide_by : NATURAL; + clk2_duty_cycle : NATURAL; + clk2_multiply_by : NATURAL; + clk2_phase_shift : STRING; + compensate_clock : STRING; + inclk0_input_frequency : NATURAL; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + operation_mode : STRING; + pll_type : STRING; + port_activeclock : STRING; + port_areset : STRING; + port_clkbad0 : STRING; + port_clkbad1 : STRING; + port_clkloss : STRING; + port_clkswitch : STRING; + port_configupdate : STRING; + port_fbin : STRING; + port_inclk0 : STRING; + port_inclk1 : STRING; + port_locked : STRING; + port_pfdena : STRING; + port_phasecounterselect : STRING; + port_phasedone : STRING; + port_phasestep : STRING; + port_phaseupdown : STRING; + port_pllena : STRING; + port_scanaclr : STRING; + port_scanclk : STRING; + port_scanclkena : STRING; + port_scandata : STRING; + port_scandataout : STRING; + port_scandone : STRING; + port_scanread : STRING; + port_scanwrite : STRING; + port_clk0 : STRING; + port_clk1 : STRING; + port_clk2 : STRING; + port_clk3 : STRING; + port_clk4 : STRING; + port_clk5 : STRING; + port_clkena0 : STRING; + port_clkena1 : STRING; + port_clkena2 : STRING; + port_clkena3 : STRING; + port_clkena4 : STRING; + port_clkena5 : STRING; + port_extclk0 : STRING; + port_extclk1 : STRING; + port_extclk2 : STRING; + port_extclk3 : STRING; + self_reset_on_loss_lock : STRING; + width_clock : NATURAL + ); + PORT ( + areset : IN STD_LOGIC ; + clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0); + inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + locked : OUT STD_LOGIC + ); + END COMPONENT; + +BEGIN + sub_wire7_bv(0 DOWNTO 0) <= "0"; + sub_wire7 <= To_stdlogicvector(sub_wire7_bv); + sub_wire4 <= sub_wire0(2); + sub_wire3 <= sub_wire0(0); + sub_wire1 <= sub_wire0(1); + c1 <= sub_wire1; + locked <= sub_wire2; + c0 <= sub_wire3; + c2 <= sub_wire4; + sub_wire5 <= inclk0; + sub_wire6 <= sub_wire7(0 DOWNTO 0) & sub_wire5; + + altpll_component : altpll + GENERIC MAP ( + bandwidth_type => "AUTO", + clk0_divide_by => 1, + clk0_duty_cycle => 50, + clk0_multiply_by => 1, + clk0_phase_shift => "-3000", + clk1_divide_by => 1, + clk1_duty_cycle => 50, + clk1_multiply_by => 1, + clk1_phase_shift => "0", + clk2_divide_by => 1, + clk2_duty_cycle => 50, + clk2_multiply_by => 2, + clk2_phase_shift => "0", + compensate_clock => "CLK1", + inclk0_input_frequency => 20000, + intended_device_family => "Cyclone II", + lpm_hint => "CBX_MODULE_PREFIX=pll", + lpm_type => "altpll", + operation_mode => "NORMAL", + pll_type => "AUTO", + port_activeclock => "PORT_UNUSED", + port_areset => "PORT_USED", + port_clkbad0 => "PORT_UNUSED", + port_clkbad1 => "PORT_UNUSED", + port_clkloss => "PORT_UNUSED", + port_clkswitch => "PORT_UNUSED", + port_configupdate => "PORT_UNUSED", + port_fbin => "PORT_UNUSED", + port_inclk0 => "PORT_USED", + port_inclk1 => "PORT_UNUSED", + port_locked => "PORT_USED", + port_pfdena => "PORT_UNUSED", + port_phasecounterselect => "PORT_UNUSED", + port_phasedone => "PORT_UNUSED", + port_phasestep => "PORT_UNUSED", + port_phaseupdown => "PORT_UNUSED", + port_pllena => "PORT_UNUSED", + port_scanaclr => "PORT_UNUSED", + port_scanclk => "PORT_UNUSED", + port_scanclkena => "PORT_UNUSED", + port_scandata => "PORT_UNUSED", + port_scandataout => "PORT_UNUSED", + port_scandone => "PORT_UNUSED", + port_scanread => "PORT_UNUSED", + port_scanwrite => "PORT_UNUSED", + port_clk0 => "PORT_USED", + port_clk1 => "PORT_USED", + port_clk2 => "PORT_USED", + port_clk3 => "PORT_UNUSED", + port_clk4 => "PORT_UNUSED", + port_clk5 => "PORT_UNUSED", + port_clkena0 => "PORT_UNUSED", + port_clkena1 => "PORT_UNUSED", + port_clkena2 => "PORT_UNUSED", + port_clkena3 => "PORT_UNUSED", + port_clkena4 => "PORT_UNUSED", + port_clkena5 => "PORT_UNUSED", + port_extclk0 => "PORT_UNUSED", + port_extclk1 => "PORT_UNUSED", + port_extclk2 => "PORT_UNUSED", + port_extclk3 => "PORT_UNUSED", + self_reset_on_loss_lock => "OFF", + width_clock => 5 + ) + PORT MAP ( + areset => areset, + inclk => sub_wire6, + clk => sub_wire0, + locked => sub_wire2 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c1" +-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" +-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1" +-- Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "1" +-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "100.000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "100.000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "100.000000" +-- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +-- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +-- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +-- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "50.000" +-- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps" +-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0" +-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "2" +-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "2" +-- Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "2" +-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "90.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "100.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "100.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "-54.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps" +-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +-- Retrieval info: PRIVATE: SPREAD_USE STRING "0" +-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +-- Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +-- Retrieval info: PRIVATE: STICKY_CLK2 STRING "1" +-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: USE_CLK0 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK1 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK2 STRING "1" +-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA2 STRING "0" +-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "-1500" +-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK1" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +-- Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +-- Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +-- Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" +-- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +-- Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +-- Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2" +-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +-- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +-- Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +-- Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2 +-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf +-- Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/vhdl/board/de2/top_level_de2.vhd b/vhdl/board/de2/top_level_de2.vhd new file mode 100644 index 0000000..ab9b756 --- /dev/null +++ b/vhdl/board/de2/top_level_de2.vhd @@ -0,0 +1,466 @@ +--+-----------------------------------+-------------------------------------+-- +--| ___ ___ | (c) 2013-2014 William R Sowerbutts |-- +--| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |-- +--| / __|/ _ \ / __|_ / _ \| | | | | |-- +--| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |-- +--| |___/\___/ \___/___\___/ \___/ | |-- +--| | http://sowerbutts.com/ |-- +--+-----------------------------------+-------------------------------------+-- +--| Top level module: connects modules to each other and the outside world |-- +--+-------------------------------------------------------------------------+-- +-- +-- See README.txt for more details +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +use work.T80_Pack.ALL; + +entity top_level is + Port ( sysclk_32m : in std_logic; + sys_clk_pad_i : in std_logic; + rst_n_pad_i : in std_logic; + leds : out std_logic_vector(4 downto 0); + reset_button : in std_logic; + console_select : in std_logic; + + -- UART0 (to FTDI USB chip, no flow control) + serial_rx : in std_logic; + serial_tx : out std_logic; + + -- UART0 (to MAX3232 level shifter chip, hardware flow control) + uart1_rx : in std_logic; + uart1_cts : in std_logic; + uart1_tx : out std_logic; + uart1_rts : out std_logic; + + -- SPI flash chip + flash_spi_cs : out std_logic; + flash_spi_clk : out std_logic; + flash_spi_mosi : out std_logic; + flash_spi_miso : in std_logic; + + -- SD card socket + sdcard_spi_cs : out std_logic; + sdcard_spi_clk : out std_logic; + sdcard_spi_mosi : out std_logic; + sdcard_spi_miso : in std_logic; + + -- SDRAM chip + SDRAM_CLK : out std_logic; + SDRAM_CKE : out std_logic; + SDRAM_CS : out std_logic; + SDRAM_nRAS : out std_logic; + SDRAM_nCAS : out std_logic; + SDRAM_nWE : out std_logic; + SDRAM_DQM : out std_logic_vector( 1 downto 0); + SDRAM_ADDR : out std_logic_vector (12 downto 0); + SDRAM_BA : out std_logic_vector( 1 downto 0); + SDRAM_DQ : inout std_logic_vector (15 downto 0) + ); +end top_level; + +architecture Behavioral of top_level is + constant clk_freq_mhz : natural := 50; -- this is the frequency which the PLL outputs, in MHz. + + -- SDRAM configuration + constant sdram_address_width : natural := 24; + constant sdram_column_bits : natural := 9; + constant cycles_per_refresh : natural := (64000*clk_freq_mhz)/8192-1; + + -- For simulation, we don't need a long init stage. but for real DRAM we need approx 101us. + -- The constant below has a different value when interpreted by the synthesis and simulator + -- tools in order to achieve the desired timing in each. + constant sdram_startup_cycles: natural := 101 * clk_freq_mhz + -- pragma translate_off + - 10000 -- reduce the value the simulator uses + -- pragma translate_on + ; + + -- signals for clocking + signal clk_feedback : std_logic; -- PLL clock feedback + signal clk_unbuffered : std_logic; -- unbuffered system clock + signal clk : std_logic; -- buffered system clock (all logic should be clocked by this) + + -- console latch + signal console_select_clk1 : std_logic; + signal console_select_sync : std_logic; + signal swap_uart01 : std_logic := '0'; + + -- system reset signals + signal power_on_reset : std_logic_vector(1 downto 0) := (others => '1'); + signal system_reset : std_logic; + signal reset_button_clk1 : std_logic; + signal reset_button_sync : std_logic; -- reset button signal, synchronised to our clock + signal reset_request_uart : std_logic; -- reset request signal from FTDI UART (when you send "!~!~!~" to the UART, this line is asserted) + + -- CPU control + signal coldboot : std_logic; + signal cpu_clk_enable : std_logic; + signal cpu_m1_cycle : std_logic; + signal cpu_req_mem : std_logic; + signal cpu_req_io : std_logic; + signal req_mem : std_logic; + signal req_io : std_logic; + signal req_read : std_logic; + signal req_write : std_logic; + signal virtual_address : std_logic_vector(15 downto 0); + signal physical_address : std_logic_vector(25 downto 0); + signal mem_wait : std_logic; + signal cpu_wait : std_logic; + signal dram_wait : std_logic; + signal mmu_wait : std_logic; + signal spimaster0_wait : std_logic; + signal spimaster1_wait : std_logic; + + -- chip selects + signal mmu_cs : std_logic; + signal rom_cs : std_logic; + signal sram_cs : std_logic; + signal dram_cs : std_logic; + signal uartA_cs : std_logic; + signal uartB_cs : std_logic; + signal uart0_cs : std_logic; + signal uart1_cs : std_logic; + signal timer_cs : std_logic; + signal spimaster0_cs : std_logic; + signal spimaster1_cs : std_logic; + signal clkscale_cs : std_logic; + signal gpio_cs : std_logic; + + -- data bus + signal cpu_data_in : std_logic_vector(7 downto 0); + signal cpu_data_out : std_logic_vector(7 downto 0); + signal rom_data_out : std_logic_vector(7 downto 0); + signal sram_data_out : std_logic_vector(7 downto 0); + signal dram_data_out : std_logic_vector(7 downto 0); + signal uart0_data_out : std_logic_vector(7 downto 0); + signal uart1_data_out : std_logic_vector(7 downto 0); + signal timer_data_out : std_logic_vector(7 downto 0); + signal spimaster0_data_out : std_logic_vector(7 downto 0); + signal spimaster1_data_out : std_logic_vector(7 downto 0); + signal mmu_data_out : std_logic_vector(7 downto 0); + signal clkscale_out : std_logic_vector(7 downto 0); + signal gpio_data_out : std_logic_vector(7 downto 0); + + -- GPIO + signal gpio_input : std_logic_vector(7 downto 0); + signal gpio_output : std_logic_vector(7 downto 0); + + -- Interrupts + signal cpu_interrupt_in : std_logic; + signal timer_interrupt : std_logic; + signal uart0_interrupt : std_logic; + signal uart1_interrupt : std_logic; + +begin + -- Hold CPU reset high for 8 clock cycles on startup, + -- and when the user presses their reset button. + process(clk) + begin + if rising_edge(clk) then + -- Xilinx advises using two flip-flops are used to bring external + -- signals which feed control logic into our clock domain. + reset_button_clk1 <= reset_button; + reset_button_sync <= reset_button_clk1; + console_select_clk1 <= console_select; + console_select_sync <= console_select_clk1; + + -- reset the system when requested + if (power_on_reset(0) = '1') then + system_reset <= '1'; + else + system_reset <= '0'; + end if; + + -- shift 0s into the power_on_reset shift register from the MSB + power_on_reset <= '0' & power_on_reset(power_on_reset'length-1 downto 1); + + -- During reset, latch the console select jumper. This is used to + -- optionally swap over the UART roles and move the system console to + -- the second serial port on the IO board. + if system_reset = '1' then + swap_uart01 <= console_select_sync; + else + swap_uart01 <= swap_uart01; + end if; + end if; + end process; + + -- GPIO input signal routing + gpio_input <= coldboot & swap_uart01 & "000000"; + + -- GPIO output signal routing + leds(0) <= gpio_output(0); + leds(1) <= gpio_output(1); + leds(2) <= gpio_output(2); + leds(3) <= gpio_output(3); + + -- User LED (LED1) on Papilio Pro indicates when the CPU is being asked to wait (eg by the SDRAM cache) + leds(4) <= cpu_wait; + + -- Interrupt signal for the CPU + cpu_interrupt_in <= (timer_interrupt or uart0_interrupt or uart1_interrupt); + + -- Z80 CPU core + cpu: entity work.Z80cpu + port map ( + reset => system_reset, + clk => clk, + clk_enable => cpu_clk_enable, + m1_cycle => cpu_m1_cycle, + interrupt => cpu_interrupt_in, + nmi => '0', + req_mem => cpu_req_mem, + req_io => cpu_req_io, + req_read => req_read, + req_write => req_write, + mem_wait => cpu_wait, + address => virtual_address, + data_in => cpu_data_in, + data_out => cpu_data_out + ); + + -- Memory management unit + mmu: entity work.MMU + port map ( + reset => system_reset, + clk => clk, + address_in => virtual_address, + address_out => physical_address, + cpu_data_in => cpu_data_out, + cpu_data_out => mmu_data_out, + req_mem_in => cpu_req_mem, + req_io_in => cpu_req_io, + req_mem_out => req_mem, + req_io_out => req_io, + req_read => req_read, + req_write => req_write, + io_cs => mmu_cs, + cpu_wait => mmu_wait, + access_violated => open -- for now!! + ); + + -- This process determines which IO or memory device the CPU is addressing + -- and asserts the appropriate chip select signals. + cs_process: process(req_mem, req_io, physical_address, virtual_address, uartA_cs, uartB_cs, swap_uart01) + begin + -- memory chip selects: default to unselected + rom_cs <= '0'; + sram_cs <= '0'; + dram_cs <= '0'; + + -- io chip selects: default to unselected + uartA_cs <= '0'; + uartB_cs <= '0'; + mmu_cs <= '0'; + timer_cs <= '0'; + spimaster0_cs <= '0'; + spimaster1_cs <= '0'; + clkscale_cs <= '0'; + gpio_cs <= '0'; + + -- memory address decoding + -- address space is organised as: + -- 0x0 000 000 - 0x0 FFF FFF 16MB DRAM (cached) (mapped to 8MB DRAM twice) + -- 0x1 000 000 - 0x1 FFF FFF 16MB DRAM (uncached) (mapped to 8MB DRAM twice) + -- 0x2 000 000 - 0x2 000 FFF 4KB monitor ROM (FPGA block RAM) + -- 0x2 001 000 - 0x2 001 FFF 4KB SRAM (FPGA block RAM) + -- 0x2 002 000 - 0x3 FFF FFF unused space for future expansion + if physical_address(25) = '0' then + -- bottom 32MB: DRAM handles this + dram_cs <= req_mem; + else + -- top 32MB: other memory devices + case physical_address(24 downto 12) is + when "0000000000000" => rom_cs <= req_mem; + when "0000000000001" => sram_cs <= req_mem; + when others => -- undecoded memory space + end case; + end if; + + -- IO address decoding + case virtual_address(7 downto 3) is + when "00000" => uartA_cs <= req_io; -- 00 ... 07 + when "00010" => timer_cs <= req_io; -- 10 ... 17 + when "00011" => spimaster0_cs <= req_io; -- 18 ... 1F + when "00100" => gpio_cs <= req_io; -- 20 ... 27 + when "00101" => uartB_cs <= req_io; -- 28 ... 2F + when "00110" => spimaster1_cs <= req_io; -- 30 ... 37 + -- unused ports + when "11110" => clkscale_cs <= req_io; -- F0 ... F7 + when "11111" => mmu_cs <= req_io; -- F8 ... FF + when others => + end case; + + -- send the UART chip select to the appropriate UART depending + -- on whether they have been swapped over or not. + if swap_uart01 = '0' then + uart0_cs <= uartB_cs; + uart1_cs <= uartA_cs; + else + uart0_cs <= uartA_cs; + uart1_cs <= uartB_cs; + end if; + end process; + + -- the selected memory device can request the CPU to wait + mem_wait <= + dram_wait when dram_cs='1' else + spimaster0_wait when spimaster0_cs='1' else + spimaster1_wait when spimaster1_cs='1' else + '0'; + + -- the MMU can, at any time, request the CPU wait (this is used when + -- translating IO to memory requests, to implement a wait state for + -- the "17th page") + cpu_wait <= (mem_wait or mmu_wait); + + -- input mux for CPU data bus + cpu_data_in <= + rom_data_out when rom_cs='1' else + dram_data_out when dram_cs='1' else + sram_data_out when sram_cs='1' else + uart0_data_out when uart0_cs='1' else + uart1_data_out when uart1_cs='1' else + timer_data_out when timer_cs='1' else + mmu_data_out when mmu_cs='1' else + spimaster0_data_out when spimaster0_cs='1' else + spimaster1_data_out when spimaster1_cs='1' else + clkscale_out when clkscale_cs='1' else + gpio_data_out when gpio_cs='1' else + rom_data_out; -- default case + + dram: entity work.DRAM + generic map( + sdram_address_width => sdram_address_width, + sdram_column_bits => sdram_column_bits, + sdram_startup_cycles=> sdram_startup_cycles, + cycles_per_refresh => cycles_per_refresh + ) + port map( + clk => clk, + reset => '0', -- important to note that we DO NOT reset the SDRAM controller on reset (it would stop refreshing, which would be bad) + + -- interface to synthetic CPU + cs => dram_cs, + req_read => req_read, + req_write => req_write, + mem_address => physical_address(24 downto 0), + mem_wait => dram_wait, + data_in => cpu_data_out, + data_out => dram_data_out, + coldboot => coldboot, + + -- interface to hardware SDRAM chip + SDRAM_CLK => open, + SDRAM_CKE => SDRAM_CKE, + SDRAM_CS => SDRAM_CS, + SDRAM_nRAS => SDRAM_nRAS, + SDRAM_nCAS => SDRAM_nCAS, + SDRAM_nWE => SDRAM_nWE, + SDRAM_DQM => SDRAM_DQM, + SDRAM_BA => SDRAM_BA, + SDRAM_ADDR => SDRAM_ADDR, + SDRAM_DQ => SDRAM_DQ + ); + + -- 4KB system ROM implemented in block RAM + rom: entity work.MonZ80 + port map( + clk => clk, + A => physical_address(11 downto 0), + D => rom_data_out + ); + + -- 4KB SRAM memory implemented in block RAM + sram: entity work.SSRAM + generic map( + AddrWidth => 12 + ) + port map( + clk => clk, + ce => sram_cs, + we => req_write, + A => physical_address(11 downto 0), + DIn => cpu_data_out, + DOut => sram_data_out + ); + + -- UART connected to FTDI USB UART + uart0: entity work.uart_interface + generic map ( watch_for_reset => 1, clk_frequency => (clk_freq_mhz * 1000000) ) + port map( + clk => clk, + reset => system_reset, + reset_out => reset_request_uart, -- result of watching for reset sequence on the input + serial_in => serial_rx, + serial_out => serial_tx, + serial_rts => open, + serial_cts => '0', + cpu_address => virtual_address(2 downto 0), + cpu_data_in => cpu_data_out, + cpu_data_out => uart0_data_out, + enable => uart0_cs, + interrupt => uart0_interrupt, + req_read => req_read, + req_write => req_write + ); + + -- Timer device (internally scales the clock to 1MHz) + timer: entity work.timer + generic map ( clk_frequency => (clk_freq_mhz * 1000000) ) + port map( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => timer_data_out, + enable => timer_cs, + req_read => req_read, + req_write => req_write, + interrupt => timer_interrupt + ); + + -- GPIO to FPGA pins and/or internal signals + gpio: entity work.gpio + port map( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => gpio_data_out, + enable => gpio_cs, + read_notwrite => req_read, + input_pins => gpio_input, + output_pins => gpio_output + ); + + -- An attempt to allow the CPU clock to be scaled back to run + -- at slower speeds without affecting the clock signal sent to + -- IO devices. Basically this was an attempt to make CP/M games + -- playable :) Very limited success. Might be simpler to remove + -- this entirely. + clkscale: entity work.clkscale + port map ( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => clkscale_out, + enable => clkscale_cs, + read_notwrite => req_read, + clk_enable => cpu_clk_enable + ); + + pll: entity work.pll + port map ( + areset => open, + inclk0 => sys_clk_pad_i, + c0 => sdram_clk, -- 100 Mhz - 180 deg + c1 => clk, -- 100 Mhz + locked => open + ); + +end Behavioral; diff --git a/vhdl/board/de2_70/SDRAM_Controller.vhd b/vhdl/board/de2_70/SDRAM_Controller.vhd new file mode 100644 index 0000000..919a0c1 --- /dev/null +++ b/vhdl/board/de2_70/SDRAM_Controller.vhd @@ -0,0 +1,473 @@ +---------------------------------------------------------------------------------- +-- Engineer: Mike Field +-- +-- Create Date: 14:09:12 09/15/2013 +-- Module Name: SDRAM_Controller - Behavioral +-- Description: Simple SDRAM controller for a Micron 48LC16M16A2-7E +-- or Micron 48LC4M16A2-7E @ 100MHz +-- Revision: +-- Revision 0.1 - Initial version +-- Revision 0.2 - Removed second clock signal that isn't needed. +-- Revision 0.3 - Added back-to-back reads and writes. +-- Revision 0.4 - Allow refeshes to be delayed till next PRECHARGE is issued, +-- Unless they get really, really delayed. If a delay occurs multiple +-- refreshes might get pushed out, but it will have avioded about +-- 50% of the refresh overhead +-- Revision 0.5 - Add more paramaters to the design, allowing it to work for both the +-- Papilio Pro and Logi-Pi +-- +-- Worst case performance (single accesses to different rows or banks) is: +-- Writes 16 cycles = 6,250,000 writes/sec = 25.0MB/s (excluding refresh overhead) +-- Reads 17 cycles = 5,882,352 reads/sec = 23.5MB/s (excluding refresh overhead) +-- +-- For 1:1 mixed reads and writes into the same row it is around 88MB/s +-- For reads or wries to the same it is can be as high as 184MB/s +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +library UNISIM; +use IEEE.NUMERIC_STD.ALL; +library altera_mf; +use altera_mf.altera_mf_components.all; + +entity SDRAM_Controller is + generic ( + sdram_address_width : natural; + sdram_column_bits : natural; + sdram_startup_cycles: natural; + cycles_per_refresh : natural + ); + Port ( clk : in STD_LOGIC; + reset : in STD_LOGIC; + + -- Interface to issue reads or write data + cmd_ready : out STD_LOGIC; -- '1' when a new command will be acted on + cmd_enable : in STD_LOGIC; -- Set to '1' to issue new command (only acted on when cmd_read = '1') + cmd_wr : in STD_LOGIC; -- Is this a write? + cmd_address : in STD_LOGIC_VECTOR(sdram_address_width-2 downto 0); -- address to read/write + cmd_byte_enable : in STD_LOGIC_VECTOR(3 downto 0); -- byte masks for the write command + cmd_data_in : in STD_LOGIC_VECTOR(31 downto 0); -- data for the write command + + data_out : out STD_LOGIC_VECTOR(31 downto 0); -- word read from SDRAM + data_out_ready : out STD_LOGIC; -- is new data ready? + + -- SDRAM signals + SDRAM_CLK : out STD_LOGIC; + SDRAM_CKE : out STD_LOGIC; + SDRAM_CS : out STD_LOGIC; + SDRAM_RAS : out STD_LOGIC; + SDRAM_CAS : out STD_LOGIC; + SDRAM_WE : out STD_LOGIC; + SDRAM_DQM : out STD_LOGIC_VECTOR( 1 downto 0); + SDRAM_ADDR : out STD_LOGIC_VECTOR(12 downto 0); + SDRAM_BA : out STD_LOGIC_VECTOR( 1 downto 0); + SDRAM_DATA : inout STD_LOGIC_VECTOR(15 downto 0)); +end SDRAM_Controller; + +architecture Behavioral of SDRAM_Controller is + -- From page 37 of MT48LC16M16A2 datasheet + -- Name (Function) CS# RAS# CAS# WE# DQM Addr Data + -- COMMAND INHIBIT (NOP) H X X X X X X + -- NO OPERATION (NOP) L H H H X X X + -- ACTIVE L L H H X Bank/row X + -- READ L H L H L/H Bank/col X + -- WRITE L H L L L/H Bank/col Valid + -- BURST TERMINATE L H H L X X Active + -- PRECHARGE L L H L X Code X + -- AUTO REFRESH L L L H X X X + -- LOAD MODE REGISTER L L L L X Op-code X + -- Write enable X X X X L X Active + -- Write inhibit X X X X H X High-Z + + -- Here are the commands mapped to constants + constant CMD_UNSELECTED : std_logic_vector(3 downto 0) := "1000"; + 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_TERMINATE : std_logic_vector(3 downto 0) := "0110"; + constant CMD_PRECHARGE : std_logic_vector(3 downto 0) := "0010"; + constant CMD_REFRESH : std_logic_vector(3 downto 0) := "0001"; + constant CMD_LOAD_MODE_REG : std_logic_vector(3 downto 0) := "0000"; + + constant MODE_REG : std_logic_vector(12 downto 0) := + -- Reserved, wr bust, OpMode, CAS Latency (2), Burst Type, Burst Length (2) + "000" & "0" & "00" & "010" & "0" & "001"; + + signal iob_command : std_logic_vector( 3 downto 0) := CMD_NOP; + signal iob_address : std_logic_vector(12 downto 0) := (others => '0'); + signal iob_data : std_logic_vector(15 downto 0) := (others => '0'); + signal iob_dqm : std_logic_vector( 1 downto 0) := (others => '0'); + signal iob_cke : std_logic := '0'; + signal iob_bank : std_logic_vector( 1 downto 0) := (others => '0'); + + attribute IOB: string; + attribute IOB of iob_command: signal is "true"; + attribute IOB of iob_address: signal is "true"; + attribute IOB of iob_dqm : signal is "true"; + attribute IOB of iob_cke : signal is "true"; + attribute IOB of iob_bank : signal is "true"; + attribute IOB of iob_data : signal is "true"; + + signal iob_data_next : std_logic_vector(15 downto 0) := (others => '0'); + signal captured_data : std_logic_vector(15 downto 0) := (others => '0'); + signal captured_data_last : std_logic_vector(15 downto 0) := (others => '0'); + signal sdram_din : std_logic_vector(15 downto 0); + attribute IOB of captured_data : signal is "true"; + + type fsm_state is (s_startup, + s_idle_in_6, s_idle_in_5, s_idle_in_4, s_idle_in_3, s_idle_in_2, s_idle_in_1, + s_idle, + s_open_in_2, s_open_in_1, + s_write_1, s_write_2, s_write_3, + s_read_1, s_read_2, s_read_3, s_read_4, + s_precharge + ); + + signal state : fsm_state := s_startup; + attribute FSM_ENCODING : string; + attribute FSM_ENCODING of state : signal is "ONE-HOT"; + + -- dual purpose counter, it counts up during the startup phase, then is used to trigger refreshes. + constant startup_refresh_max : unsigned(13 downto 0) := (others => '1'); + signal startup_refresh_count : unsigned(13 downto 0) := startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + + -- logic to decide when to refresh + signal pending_refresh : std_logic := '0'; + signal forcing_refresh : std_logic := '0'; + + -- The incoming address is split into these three values + signal addr_row : std_logic_vector(12 downto 0) := (others => '0'); + signal addr_col : std_logic_vector(12 downto 0) := (others => '0'); + signal addr_bank : std_logic_vector( 1 downto 0) := (others => '0'); + + signal dqm_sr : std_logic_vector( 3 downto 0) := (others => '1'); -- an extra two bits in case CAS=3 + + -- signals to hold the requested transaction before it is completed + signal save_wr : std_logic := '0'; + signal save_row : std_logic_vector(12 downto 0); + signal save_bank : std_logic_vector( 1 downto 0); + signal save_col : std_logic_vector(12 downto 0); + signal save_data_in : std_logic_vector(31 downto 0); + signal save_byte_enable : std_logic_vector( 3 downto 0); + + -- control when new transactions are accepted + signal ready_for_new : std_logic := '0'; + signal got_transaction : std_logic := '0'; + + signal can_back_to_back : std_logic := '0'; + + -- signal to control the Hi-Z state of the DQ bus + signal iob_dq_hiz : std_logic := '1'; + + -- signals for when to read the data off of the bus + signal data_ready_delay : std_logic_vector( 4 downto 0); + + -- bit indexes used when splitting the address into row/colum/bank. + constant start_of_col : natural := 0; + constant end_of_col : natural := sdram_column_bits-2; + constant start_of_bank : natural := sdram_column_bits-1; + constant end_of_bank : natural := sdram_column_bits; + constant start_of_row : natural := sdram_column_bits+1; + constant end_of_row : natural := sdram_address_width-2; + constant prefresh_cmd : natural := 10; +begin + -- Indicate the need to refresh when the counter is 2048, + -- Force a refresh when the counter is 4096 - (if a refresh is forced, + -- multiple refresshes will be forced until the counter is below 2048 + pending_refresh <= startup_refresh_count(11); + forcing_refresh <= startup_refresh_count(12); + + -- tell the outside world when we can accept a new transaction; + cmd_ready <= ready_for_new; + ---------------------------------------------------------------------------- + -- Seperate the address into row / bank / address + ---------------------------------------------------------------------------- + addr_row(end_of_row-start_of_row downto 0) <= cmd_address(end_of_row downto start_of_row); -- 12:0 <= 22:10 + addr_bank <= cmd_address(end_of_bank downto start_of_bank); -- 1:0 <= 9:8 + addr_col(sdram_column_bits-1 downto 0) <= cmd_address(end_of_col downto start_of_col) & '0'; -- 8:0 <= 7:0 & '0' + --addr_row(12 downto 0) <= cmd_address(22 downto 10); -- 12:0 <= 22:10 + --addr_bank <= cmd_address( 9 downto 8); -- 1:0 <= 9:8 + --addr_col(8 downto 0) <= cmd_address( 7 downto 0) & '0'; -- 8:0 <= 7:0 & '0' + + ----------------------------------------------- + --!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + --!! Ensure that all outputs are registered. !! + --!! Check the pinout report to be sure !! + --!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ----------------------------------------------- + sdram_cke <= iob_cke; + sdram_CS <= iob_command(3); + sdram_RAS <= iob_command(2); + sdram_CAS <= iob_command(1); + sdram_WE <= iob_command(0); + sdram_dqm <= iob_dqm; + sdram_ba <= iob_bank; + sdram_addr <= iob_address; + sdram_din <= sdram_data; + sdram_data <= iob_data when iob_dq_hiz = '0' else (others => 'Z'); + + --------------------------------------------------------------- + -- Explicitly set up the tristate I/O buffers on the DQ signals + --------------------------------------------------------------- +--iob_dq_g: for i in 0 to 15 generate +-- begin +--iob_dq_iob: altiobuf_bidir +-- generic map (number_of_channels => 1) +-- port map ( dataout(0) => sdram_din(i), dataio(0) => sdram_data(i), datain(0) => iob_data(i), oe(0) => iob_dq_hiz); +--end generate; + +capture_proc: process(clk) + begin + if rising_edge(clk) then + captured_data <= sdram_din; + end if; + end process; + +main_proc: process(clk) + begin + if rising_edge(clk) then + captured_data_last <= captured_data; + + ------------------------------------------------ + -- Default state is to do nothing + ------------------------------------------------ + iob_command <= CMD_NOP; + iob_address <= (others => '0'); + iob_bank <= (others => '0'); + + ------------------------------------------------ + -- countdown for initialisation & refresh + ------------------------------------------------ + startup_refresh_count <= startup_refresh_count+1; + + ------------------------------------------------------------------- + -- It we are ready for a new tranasction and one is being presented + -- then accept it. Also remember what we are reading or writing, + -- and if it can be back-to-backed with the last transaction + ------------------------------------------------------------------- + if ready_for_new = '1' and cmd_enable = '1' then + if save_bank = addr_bank and save_row = addr_row then + can_back_to_back <= '1'; + else + can_back_to_back <= '0'; + end if; + save_row <= addr_row; + save_bank <= addr_bank; + save_col <= addr_col; + save_wr <= cmd_wr; + save_data_in <= cmd_data_in; + save_byte_enable <= cmd_byte_enable; + got_transaction <= '1'; + ready_for_new <= '0'; + end if; + + ------------------------------------------------ + -- Handle the data coming back from the + -- SDRAM for the Read transaction + ------------------------------------------------ + data_out_ready <= '0'; + if data_ready_delay(0) = '1' then + data_out <= captured_data & captured_data_last; + data_out_ready <= '1'; + end if; + + ---------------------------------------------------------------------------- + -- update shift registers used to choose when to present data to/from memory + ---------------------------------------------------------------------------- + data_ready_delay <= '0' & data_ready_delay(data_ready_delay'high downto 1); + iob_dqm <= dqm_sr(1 downto 0); + dqm_sr <= "11" & dqm_sr(dqm_sr'high downto 2); + + case state is + when s_startup => + ------------------------------------------------------------------------ + -- This is the initial startup state, where we wait for at least 100us + -- before starting the start sequence + -- + -- The initialisation is sequence is + -- * de-assert SDRAM_CKE + -- * 100us wait, + -- * assert SDRAM_CKE + -- * wait at least one cycle, + -- * PRECHARGE + -- * wait 2 cycles + -- * REFRESH, + -- * tREF wait + -- * REFRESH, + -- * tREF wait + -- * LOAD_MODE_REG + -- * 2 cycles wait + ------------------------------------------------------------------------ + iob_CKE <= '1'; + + -- All the commands during the startup are NOPS, except these + if startup_refresh_count = startup_refresh_max-31 then + -- ensure all rows are closed + iob_command <= CMD_PRECHARGE; + iob_address(prefresh_cmd) <= '1'; -- all banks + iob_bank <= (others => '0'); + elsif startup_refresh_count = startup_refresh_max-23 then + -- these refreshes need to be at least tREF (66ns) apart + iob_command <= CMD_REFRESH; + elsif startup_refresh_count = startup_refresh_max-15 then + iob_command <= CMD_REFRESH; + elsif startup_refresh_count = startup_refresh_max-7 then + -- Now load the mode register + iob_command <= CMD_LOAD_MODE_REG; + iob_address <= MODE_REG; + end if; + + ------------------------------------------------------ + -- if startup is coomplete then go into idle mode, + -- get prepared to accept a new command, and schedule + -- the first refresh cycle + ------------------------------------------------------ + if startup_refresh_count = 0 then + state <= s_idle; + ready_for_new <= '1'; + got_transaction <= '0'; + startup_refresh_count <= to_unsigned(2048 - cycles_per_refresh+1,14); + end if; + + when s_idle_in_6 => state <= s_idle_in_5; + when s_idle_in_5 => state <= s_idle_in_4; + when s_idle_in_4 => state <= s_idle_in_3; + when s_idle_in_3 => state <= s_idle_in_2; + when s_idle_in_2 => state <= s_idle_in_1; + when s_idle_in_1 => state <= s_idle; + + when s_idle => + -- Priority is to issue a refresh if one is outstanding + if pending_refresh = '1' or forcing_refresh = '1' then + ------------------------------------------------------------------------ + -- Start the refresh cycle. + -- This tasks tRFC (66ns), so 6 idle cycles are needed @ 100MHz + ------------------------------------------------------------------------ + state <= s_idle_in_3; + iob_command <= CMD_REFRESH; + startup_refresh_count <= startup_refresh_count - cycles_per_refresh+1; + elsif got_transaction = '1' then + -------------------------------- + -- Start the read or write cycle. + -- First task is to open the row + -------------------------------- + state <= s_open_in_1; + iob_command <= CMD_ACTIVE; + iob_address <= save_row; + iob_bank <= save_bank; + end if; + + -------------------------------------------- + -- Opening the row ready for reads or writes + -------------------------------------------- + when s_open_in_2 => state <= s_open_in_1; + + when s_open_in_1 => + -- still waiting for row to open + if save_wr = '1' then + state <= s_write_1; + iob_dq_hiz <= '0'; + iob_data <= save_data_in(15 downto 0); -- get the DQ bus out of HiZ early + else + iob_dq_hiz <= '1'; + state <= s_read_1; + end if; + -- we will be ready for a new transaction next cycle! + ready_for_new <= '1'; + got_transaction <= '0'; + + ---------------------------------- + -- Processing the read transaction + ---------------------------------- + when s_read_1 => + state <= s_read_2; + iob_command <= CMD_READ; + iob_address <= save_col; + iob_bank <= save_bank; + iob_address(prefresh_cmd) <= '0'; -- A10 actually matters - it selects auto precharge + + -- Schedule reading the data values off the bus + data_ready_delay(data_ready_delay'high) <= '1'; + + -- Set the data masks to read all bytes + iob_dqm <= (others => '0'); + dqm_sr(1 downto 0) <= (others => '0'); + + when s_read_2 => + state <= s_read_3; + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + end if; + end if; + + when s_read_3 => + state <= s_read_4; + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + end if; + end if; + + when s_read_4 => + state <= s_precharge; + -- can we do back-to-back read? + if forcing_refresh = '0' and got_transaction = '1' and can_back_to_back = '1' then + if save_wr = '0' then + state <= s_read_1; + ready_for_new <= '1'; -- we will be ready for a new transaction next cycle! + else + state <= s_open_in_2; -- we have to wait for the read data to come back before we swutch the bus into HiZ + end if; + end if; + + ------------------------------------------------------------------ + -- Processing the write transaction + ------------------------------------------------------------------- + when s_write_1 => + state <= s_write_2; + iob_command <= CMD_WRITE; + iob_address <= save_col; + iob_address(prefresh_cmd) <= '0'; -- A10 actually matters - it selects auto precharge + iob_bank <= save_bank; + iob_dqm <= NOT save_byte_enable(1 downto 0); + dqm_sr(1 downto 0) <= NOT save_byte_enable(3 downto 2); + iob_data <= save_data_in(15 downto 0); + iob_data_next <= save_data_in(31 downto 16); + + when s_write_2 => + state <= s_write_3; + iob_data <= iob_data_next; + + when s_write_3 => -- must wait tRDL, hence the extra idle state + iob_dq_hiz <= '1'; + state <= s_precharge; + + ------------------------------------------------------------------- + -- Closing the row off (this closes all banks) + ------------------------------------------------------------------- + when s_precharge => + state <= s_idle_in_3; + iob_command <= CMD_PRECHARGE; + iob_address(prefresh_cmd) <= '1'; -- A10 actually matters - it selects all banks or just one + + ------------------------------------------------------------------- + -- We should never get here, but if we do then reset the memory + ------------------------------------------------------------------- + when others => + state <= s_startup; + ready_for_new <= '0'; + startup_refresh_count <= startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + end case; + + if reset = '1' then -- Sync reset + state <= s_startup; + ready_for_new <= '0'; + startup_refresh_count <= startup_refresh_max-to_unsigned(sdram_startup_cycles,14); + end if; + end if; + end process; +end Behavioral; diff --git a/vhdl/board/de2_70/pll_de2_70.vhd b/vhdl/board/de2_70/pll_de2_70.vhd new file mode 100644 index 0000000..c270ca1 --- /dev/null +++ b/vhdl/board/de2_70/pll_de2_70.vhd @@ -0,0 +1,429 @@ +-- megafunction wizard: %ALTPLL% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altpll + +-- ============================================================ +-- File Name: pll.vhd +-- Megafunction Name(s): +-- altpll +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.1.0 Build 162 10/23/2013 SJ Web Edition +-- ************************************************************ + + +--Copyright (C) 1991-2013 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY pll IS + PORT + ( + areset : IN STD_LOGIC := '0'; + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + c1 : OUT STD_LOGIC ; + c2 : OUT STD_LOGIC ; + locked : OUT STD_LOGIC + ); +END pll; + + +ARCHITECTURE SYN OF pll IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (4 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC ; + SIGNAL sub_wire2 : STD_LOGIC ; + SIGNAL sub_wire3 : STD_LOGIC ; + SIGNAL sub_wire4 : STD_LOGIC ; + SIGNAL sub_wire5 : STD_LOGIC ; + SIGNAL sub_wire6 : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL sub_wire7_bv : BIT_VECTOR (0 DOWNTO 0); + SIGNAL sub_wire7 : STD_LOGIC_VECTOR (0 DOWNTO 0); + + + + COMPONENT altpll + GENERIC ( + bandwidth_type : STRING; + clk0_divide_by : NATURAL; + clk0_duty_cycle : NATURAL; + clk0_multiply_by : NATURAL; + clk0_phase_shift : STRING; + clk1_divide_by : NATURAL; + clk1_duty_cycle : NATURAL; + clk1_multiply_by : NATURAL; + clk1_phase_shift : STRING; + clk2_divide_by : NATURAL; + clk2_duty_cycle : NATURAL; + clk2_multiply_by : NATURAL; + clk2_phase_shift : STRING; + compensate_clock : STRING; + inclk0_input_frequency : NATURAL; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + operation_mode : STRING; + pll_type : STRING; + port_activeclock : STRING; + port_areset : STRING; + port_clkbad0 : STRING; + port_clkbad1 : STRING; + port_clkloss : STRING; + port_clkswitch : STRING; + port_configupdate : STRING; + port_fbin : STRING; + port_inclk0 : STRING; + port_inclk1 : STRING; + port_locked : STRING; + port_pfdena : STRING; + port_phasecounterselect : STRING; + port_phasedone : STRING; + port_phasestep : STRING; + port_phaseupdown : STRING; + port_pllena : STRING; + port_scanaclr : STRING; + port_scanclk : STRING; + port_scanclkena : STRING; + port_scandata : STRING; + port_scandataout : STRING; + port_scandone : STRING; + port_scanread : STRING; + port_scanwrite : STRING; + port_clk0 : STRING; + port_clk1 : STRING; + port_clk2 : STRING; + port_clk3 : STRING; + port_clk4 : STRING; + port_clk5 : STRING; + port_clkena0 : STRING; + port_clkena1 : STRING; + port_clkena2 : STRING; + port_clkena3 : STRING; + port_clkena4 : STRING; + port_clkena5 : STRING; + port_extclk0 : STRING; + port_extclk1 : STRING; + port_extclk2 : STRING; + port_extclk3 : STRING; + self_reset_on_loss_lock : STRING; + width_clock : NATURAL + ); + PORT ( + areset : IN STD_LOGIC ; + clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0); + inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + locked : OUT STD_LOGIC + ); + END COMPONENT; + +BEGIN + sub_wire7_bv(0 DOWNTO 0) <= "0"; + sub_wire7 <= To_stdlogicvector(sub_wire7_bv); + sub_wire4 <= sub_wire0(2); + sub_wire3 <= sub_wire0(0); + sub_wire1 <= sub_wire0(1); + c1 <= sub_wire1; + locked <= sub_wire2; + c0 <= sub_wire3; + c2 <= sub_wire4; + sub_wire5 <= inclk0; + sub_wire6 <= sub_wire7(0 DOWNTO 0) & sub_wire5; + + altpll_component : altpll + GENERIC MAP ( + bandwidth_type => "AUTO", + clk0_divide_by => 1, + clk0_duty_cycle => 50, + clk0_multiply_by => 1, + clk0_phase_shift => "-3000", + clk1_divide_by => 1, + clk1_duty_cycle => 50, + clk1_multiply_by => 1, + clk1_phase_shift => "0", + clk2_divide_by => 1, + clk2_duty_cycle => 50, + clk2_multiply_by => 2, + clk2_phase_shift => "0", + compensate_clock => "CLK1", + inclk0_input_frequency => 20000, + intended_device_family => "Cyclone II", + lpm_hint => "CBX_MODULE_PREFIX=pll", + lpm_type => "altpll", + operation_mode => "NORMAL", + pll_type => "AUTO", + port_activeclock => "PORT_UNUSED", + port_areset => "PORT_USED", + port_clkbad0 => "PORT_UNUSED", + port_clkbad1 => "PORT_UNUSED", + port_clkloss => "PORT_UNUSED", + port_clkswitch => "PORT_UNUSED", + port_configupdate => "PORT_UNUSED", + port_fbin => "PORT_UNUSED", + port_inclk0 => "PORT_USED", + port_inclk1 => "PORT_UNUSED", + port_locked => "PORT_USED", + port_pfdena => "PORT_UNUSED", + port_phasecounterselect => "PORT_UNUSED", + port_phasedone => "PORT_UNUSED", + port_phasestep => "PORT_UNUSED", + port_phaseupdown => "PORT_UNUSED", + port_pllena => "PORT_UNUSED", + port_scanaclr => "PORT_UNUSED", + port_scanclk => "PORT_UNUSED", + port_scanclkena => "PORT_UNUSED", + port_scandata => "PORT_UNUSED", + port_scandataout => "PORT_UNUSED", + port_scandone => "PORT_UNUSED", + port_scanread => "PORT_UNUSED", + port_scanwrite => "PORT_UNUSED", + port_clk0 => "PORT_USED", + port_clk1 => "PORT_USED", + port_clk2 => "PORT_USED", + port_clk3 => "PORT_UNUSED", + port_clk4 => "PORT_UNUSED", + port_clk5 => "PORT_UNUSED", + port_clkena0 => "PORT_UNUSED", + port_clkena1 => "PORT_UNUSED", + port_clkena2 => "PORT_UNUSED", + port_clkena3 => "PORT_UNUSED", + port_clkena4 => "PORT_UNUSED", + port_clkena5 => "PORT_UNUSED", + port_extclk0 => "PORT_UNUSED", + port_extclk1 => "PORT_UNUSED", + port_extclk2 => "PORT_UNUSED", + port_extclk3 => "PORT_UNUSED", + self_reset_on_loss_lock => "OFF", + width_clock => 5 + ) + PORT MAP ( + areset => areset, + inclk => sub_wire6, + clk => sub_wire0, + locked => sub_wire2 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c1" +-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" +-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1" +-- Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "1" +-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "100.000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "100.000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "100.000000" +-- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +-- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +-- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +-- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "50.000" +-- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps" +-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0" +-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "2" +-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "2" +-- Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "2" +-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "90.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "100.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "100.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "-54.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps" +-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +-- Retrieval info: PRIVATE: SPREAD_USE STRING "0" +-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +-- Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +-- Retrieval info: PRIVATE: STICKY_CLK2 STRING "1" +-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: USE_CLK0 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK1 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK2 STRING "1" +-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA2 STRING "0" +-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "-1500" +-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "1" +-- Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "2" +-- Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK1" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +-- Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +-- Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +-- Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" +-- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +-- Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +-- Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2" +-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +-- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +-- Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +-- Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2 +-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf +-- Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/vhdl/board/de2_70/top_level_de2_70.vhd b/vhdl/board/de2_70/top_level_de2_70.vhd new file mode 100644 index 0000000..beeb818 --- /dev/null +++ b/vhdl/board/de2_70/top_level_de2_70.vhd @@ -0,0 +1,465 @@ +--+-----------------------------------+-------------------------------------+-- +--| ___ ___ | (c) 2013-2014 William R Sowerbutts |-- +--| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |-- +--| / __|/ _ \ / __|_ / _ \| | | | | |-- +--| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |-- +--| |___/\___/ \___/___\___/ \___/ | |-- +--| | http://sowerbutts.com/ |-- +--+-----------------------------------+-------------------------------------+-- +--| Top level module: connects modules to each other and the outside world |-- +--+-------------------------------------------------------------------------+-- +-- +-- See README.txt for more details +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity top_level is + Port ( sysclk_32m : in std_logic; + sys_clk_pad_i : in std_logic; + rst_n_pad_i : in std_logic; + leds : out std_logic_vector(4 downto 0); + reset_button : in std_logic; + console_select : in std_logic; + + -- UART0 (to FTDI USB chip, no flow control) + serial_rx : in std_logic; + serial_tx : out std_logic; + + -- UART0 (to MAX3232 level shifter chip, hardware flow control) + uart1_rx : in std_logic; + uart1_cts : in std_logic; + uart1_tx : out std_logic; + uart1_rts : out std_logic; + + -- SPI flash chip + flash_spi_cs : out std_logic; + flash_spi_clk : out std_logic; + flash_spi_mosi : out std_logic; + flash_spi_miso : in std_logic; + + -- SD card socket + sdcard_spi_cs : out std_logic; + sdcard_spi_clk : out std_logic; + sdcard_spi_mosi : out std_logic; + sdcard_spi_miso : in std_logic; + + -- SDRAM chip + SDRAM_CLK : out std_logic; + SDRAM_CKE : out std_logic; + SDRAM_CS : out std_logic; + SDRAM_nRAS : out std_logic; + SDRAM_nCAS : out std_logic; + SDRAM_nWE : out std_logic; + SDRAM_DQM : out std_logic_vector( 1 downto 0); + SDRAM_ADDR : out std_logic_vector (12 downto 0); + SDRAM_BA : out std_logic_vector( 1 downto 0); + SDRAM_DQ : inout std_logic_vector (15 downto 0) + ); +end top_level; + +architecture Behavioral of top_level is + constant clk_freq_mhz : natural := 50; -- this is the frequency which the PLL outputs, in MHz. + + -- SDRAM configuration + constant sdram_address_width : natural := 24; + constant sdram_column_bits : natural := 9; + constant cycles_per_refresh : natural := (64000*clk_freq_mhz)/8192-1; + + -- For simulation, we don't need a long init stage. but for real DRAM we need approx 101us. + -- The constant below has a different value when interpreted by the synthesis and simulator + -- tools in order to achieve the desired timing in each. + constant sdram_startup_cycles: natural := 101 * clk_freq_mhz + -- pragma translate_off + - 10000 -- reduce the value the simulator uses + -- pragma translate_on + ; + + -- signals for clocking + signal clk_feedback : std_logic; -- PLL clock feedback + signal clk_unbuffered : std_logic; -- unbuffered system clock + signal clk : std_logic; -- buffered system clock (all logic should be clocked by this) + + -- console latch + signal console_select_clk1 : std_logic; + signal console_select_sync : std_logic; + signal swap_uart01 : std_logic := '0'; + + -- system reset signals + signal power_on_reset : std_logic_vector(1 downto 0) := (others => '1'); + signal system_reset : std_logic; + signal reset_button_clk1 : std_logic; + signal reset_button_sync : std_logic; -- reset button signal, synchronised to our clock + signal reset_request_uart : std_logic; -- reset request signal from FTDI UART (when you send "!~!~!~" to the UART, this line is asserted) + + -- CPU control + signal coldboot : std_logic; + signal cpu_clk_enable : std_logic; + signal cpu_m1_cycle : std_logic; + signal cpu_req_mem : std_logic; + signal cpu_req_io : std_logic; + signal req_mem : std_logic; + signal req_io : std_logic; + signal req_read : std_logic; + signal req_write : std_logic; + signal virtual_address : std_logic_vector(15 downto 0); + signal physical_address : std_logic_vector(25 downto 0); + signal mem_wait : std_logic; + signal cpu_wait : std_logic; + signal dram_wait : std_logic; + signal mmu_wait : std_logic; + signal spimaster0_wait : std_logic; + signal spimaster1_wait : std_logic; + + -- chip selects + signal mmu_cs : std_logic; + signal rom_cs : std_logic; + signal sram_cs : std_logic; + signal dram_cs : std_logic; + signal uartA_cs : std_logic; + signal uartB_cs : std_logic; + signal uart0_cs : std_logic; + signal uart1_cs : std_logic; + signal timer_cs : std_logic; + signal spimaster0_cs : std_logic; + signal spimaster1_cs : std_logic; + signal clkscale_cs : std_logic; + signal gpio_cs : std_logic; + + -- data bus + signal cpu_data_in : std_logic_vector(7 downto 0); + signal cpu_data_out : std_logic_vector(7 downto 0); + signal rom_data_out : std_logic_vector(7 downto 0); + signal sram_data_out : std_logic_vector(7 downto 0); + signal dram_data_out : std_logic_vector(7 downto 0); + signal uart0_data_out : std_logic_vector(7 downto 0); + signal uart1_data_out : std_logic_vector(7 downto 0); + signal timer_data_out : std_logic_vector(7 downto 0); + signal spimaster0_data_out : std_logic_vector(7 downto 0); + signal spimaster1_data_out : std_logic_vector(7 downto 0); + signal mmu_data_out : std_logic_vector(7 downto 0); + signal clkscale_out : std_logic_vector(7 downto 0); + signal gpio_data_out : std_logic_vector(7 downto 0); + + -- GPIO + signal gpio_input : std_logic_vector(7 downto 0); + signal gpio_output : std_logic_vector(7 downto 0); + + -- Interrupts + signal cpu_interrupt_in : std_logic; + signal timer_interrupt : std_logic; + signal uart0_interrupt : std_logic; + signal uart1_interrupt : std_logic; + +begin + -- Hold CPU reset high for 8 clock cycles on startup, + -- and when the user presses their reset button. + process(clk) + begin + if rising_edge(clk) then + -- Xilinx advises using two flip-flops are used to bring external + -- signals which feed control logic into our clock domain. + reset_button_clk1 <= reset_button; + reset_button_sync <= reset_button_clk1; + console_select_clk1 <= console_select; + console_select_sync <= console_select_clk1; + + -- reset the system when requested + if (power_on_reset(0) = '1') then + system_reset <= '1'; + else + system_reset <= '0'; + end if; + + -- shift 0s into the power_on_reset shift register from the MSB + power_on_reset <= '0' & power_on_reset(power_on_reset'length-1 downto 1); + + -- During reset, latch the console select jumper. This is used to + -- optionally swap over the UART roles and move the system console to + -- the second serial port on the IO board. + if system_reset = '1' then + swap_uart01 <= console_select_sync; + else + swap_uart01 <= swap_uart01; + end if; + end if; + end process; + + -- GPIO input signal routing + gpio_input <= coldboot & swap_uart01 & "000000"; + + -- GPIO output signal routing + leds(0) <= gpio_output(0); + leds(1) <= gpio_output(1); + leds(2) <= gpio_output(2); + leds(3) <= gpio_output(3); + + -- User LED (LED1) on Papilio Pro indicates when the CPU is being asked to wait (eg by the SDRAM cache) + leds(4) <= cpu_wait; + + -- Interrupt signal for the CPU + cpu_interrupt_in <= (timer_interrupt or uart0_interrupt or uart1_interrupt); + + -- Z80 CPU core + cpu: entity work.Z80cpu + port map ( + reset => system_reset, + clk => clk, + clk_enable => cpu_clk_enable, + m1_cycle => cpu_m1_cycle, + interrupt => cpu_interrupt_in, + nmi => '0', + req_mem => cpu_req_mem, + req_io => cpu_req_io, + req_read => req_read, + req_write => req_write, + mem_wait => cpu_wait, + address => virtual_address, + data_in => cpu_data_in, + data_out => cpu_data_out + ); + + -- Memory management unit + mmu: entity work.MMU + port map ( + reset => system_reset, + clk => clk, + address_in => virtual_address, + address_out => physical_address, + cpu_data_in => cpu_data_out, + cpu_data_out => mmu_data_out, + req_mem_in => cpu_req_mem, + req_io_in => cpu_req_io, + req_mem_out => req_mem, + req_io_out => req_io, + req_read => req_read, + req_write => req_write, + io_cs => mmu_cs, + cpu_wait => mmu_wait, + access_violated => open -- for now!! + ); + + -- This process determines which IO or memory device the CPU is addressing + -- and asserts the appropriate chip select signals. + cs_process: process(req_mem, req_io, physical_address, virtual_address, uartA_cs, uartB_cs, swap_uart01) + begin + -- memory chip selects: default to unselected + rom_cs <= '0'; + sram_cs <= '0'; + dram_cs <= '0'; + + -- io chip selects: default to unselected + uartA_cs <= '0'; + uartB_cs <= '0'; + mmu_cs <= '0'; + timer_cs <= '0'; + spimaster0_cs <= '0'; + spimaster1_cs <= '0'; + clkscale_cs <= '0'; + gpio_cs <= '0'; + + -- memory address decoding + -- address space is organised as: + -- 0x0 000 000 - 0x0 FFF FFF 16MB DRAM (cached) (mapped to 8MB DRAM twice) + -- 0x1 000 000 - 0x1 FFF FFF 16MB DRAM (uncached) (mapped to 8MB DRAM twice) + -- 0x2 000 000 - 0x2 000 FFF 4KB monitor ROM (FPGA block RAM) + -- 0x2 001 000 - 0x2 001 FFF 4KB SRAM (FPGA block RAM) + -- 0x2 002 000 - 0x3 FFF FFF unused space for future expansion + if physical_address(25) = '0' then + -- bottom 32MB: DRAM handles this + dram_cs <= req_mem; + else + -- top 32MB: other memory devices + case physical_address(24 downto 12) is + when "0000000000000" => rom_cs <= req_mem; + when "0000000000001" => sram_cs <= req_mem; + when others => -- undecoded memory space + end case; + end if; + + -- IO address decoding + case virtual_address(7 downto 3) is + when "00000" => uartA_cs <= req_io; -- 00 ... 07 + when "00010" => timer_cs <= req_io; -- 10 ... 17 + when "00011" => spimaster0_cs <= req_io; -- 18 ... 1F + when "00100" => gpio_cs <= req_io; -- 20 ... 27 + when "00101" => uartB_cs <= req_io; -- 28 ... 2F + when "00110" => spimaster1_cs <= req_io; -- 30 ... 37 + -- unused ports + when "11110" => clkscale_cs <= req_io; -- F0 ... F7 + when "11111" => mmu_cs <= req_io; -- F8 ... FF + when others => + end case; + + -- send the UART chip select to the appropriate UART depending + -- on whether they have been swapped over or not. + if swap_uart01 = '0' then + uart0_cs <= uartB_cs; + uart1_cs <= uartA_cs; + else + uart0_cs <= uartA_cs; + uart1_cs <= uartB_cs; + end if; + end process; + + -- the selected memory device can request the CPU to wait + mem_wait <= + dram_wait when dram_cs='1' else + spimaster0_wait when spimaster0_cs='1' else + spimaster1_wait when spimaster1_cs='1' else + '0'; + + -- the MMU can, at any time, request the CPU wait (this is used when + -- translating IO to memory requests, to implement a wait state for + -- the "17th page") + cpu_wait <= (mem_wait or mmu_wait); + + -- input mux for CPU data bus + cpu_data_in <= + rom_data_out when rom_cs='1' else + dram_data_out when dram_cs='1' else + sram_data_out when sram_cs='1' else + uart0_data_out when uart0_cs='1' else + uart1_data_out when uart1_cs='1' else + timer_data_out when timer_cs='1' else + mmu_data_out when mmu_cs='1' else + spimaster0_data_out when spimaster0_cs='1' else + spimaster1_data_out when spimaster1_cs='1' else + clkscale_out when clkscale_cs='1' else + gpio_data_out when gpio_cs='1' else + rom_data_out; -- default case + + dram: entity work.DRAM + generic map( + sdram_address_width => sdram_address_width, + sdram_column_bits => sdram_column_bits, + sdram_startup_cycles=> sdram_startup_cycles, + cycles_per_refresh => cycles_per_refresh + ) + port map( + clk => clk, + reset => '0', -- important to note that we DO NOT reset the SDRAM controller on reset (it would stop refreshing, which would be bad) + + -- interface to synthetic CPU + cs => dram_cs, + req_read => req_read, + req_write => req_write, + mem_address => physical_address(24 downto 0), + mem_wait => dram_wait, + data_in => cpu_data_out, + data_out => dram_data_out, + coldboot => coldboot, + + -- interface to hardware SDRAM chip + SDRAM_CLK => open, + SDRAM_CKE => SDRAM_CKE, + SDRAM_CS => SDRAM_CS, + SDRAM_nRAS => SDRAM_nRAS, + SDRAM_nCAS => SDRAM_nCAS, + SDRAM_nWE => SDRAM_nWE, + SDRAM_DQM => SDRAM_DQM, + SDRAM_BA => SDRAM_BA, + SDRAM_ADDR => SDRAM_ADDR, + SDRAM_DQ => SDRAM_DQ + ); + + -- 4KB system ROM implemented in block RAM + rom: entity work.MonZ80 + port map( + clk => clk, + A => physical_address(11 downto 0), + D => rom_data_out + ); + + -- 4KB SRAM memory implemented in block RAM + sram: entity work.SSRAM + generic map( + AddrWidth => 12 + ) + port map( + clk => clk, + ce => sram_cs, + we => req_write, + A => physical_address(11 downto 0), + DIn => cpu_data_out, + DOut => sram_data_out + ); + + -- UART connected to FTDI USB UART + uart0: entity work.uart_interface + generic map ( watch_for_reset => 1, clk_frequency => (clk_freq_mhz * 1000000) ) + port map( + clk => clk, + reset => system_reset, + reset_out => reset_request_uart, -- result of watching for reset sequence on the input + serial_in => serial_rx, + serial_out => serial_tx, + serial_rts => open, + serial_cts => '0', + cpu_address => virtual_address(2 downto 0), + cpu_data_in => cpu_data_out, + cpu_data_out => uart0_data_out, + enable => uart0_cs, + interrupt => uart0_interrupt, + req_read => req_read, + req_write => req_write + ); + + -- Timer device (internally scales the clock to 1MHz) + timer: entity work.timer + generic map ( clk_frequency => (clk_freq_mhz * 1000000) ) + port map( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => timer_data_out, + enable => timer_cs, + req_read => req_read, + req_write => req_write, + interrupt => timer_interrupt + ); + + -- GPIO to FPGA pins and/or internal signals + gpio: entity work.gpio + port map( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => gpio_data_out, + enable => gpio_cs, + read_notwrite => req_read, + input_pins => gpio_input, + output_pins => gpio_output + ); + + -- An attempt to allow the CPU clock to be scaled back to run + -- at slower speeds without affecting the clock signal sent to + -- IO devices. Basically this was an attempt to make CP/M games + -- playable :) Very limited success. Might be simpler to remove + -- this entirely. + clkscale: entity work.clkscale + port map ( + clk => clk, + reset => system_reset, + cpu_address => virtual_address(2 downto 0), + data_in => cpu_data_out, + data_out => clkscale_out, + enable => clkscale_cs, + read_notwrite => req_read, + clk_enable => cpu_clk_enable + ); + + pll: entity work.pll + port map ( + areset => open, + inclk0 => sys_clk_pad_i, + c0 => sdram_clk, -- 100 Mhz - 180 deg + c1 => clk, -- 100 Mhz + locked => open + ); + +end Behavioral;