Kaynağa Gözat

Merge branch 'master' into Oliver_FPA

# Conflicts:
#	Makefile
#	src/root.sv
Oliver Jaison 4 yıl önce
ebeveyn
işleme
41f0b317fc

+ 19 - 3
.gitignore

@@ -1,6 +1,22 @@
-/*
-!/src/
+# Ignore all, making this a whitelist
+*
+!*/
+
+# Exclude rules from ignore
 !/altera_devel.qpf
 !/altera_devel.qsf
 !/Makefile
-!/readme.md
+!*.md
+!*.v
+!*.sv
+!*.py
+!sim_*.do
+!*.qip
+
+# Making sure nothing from there will be picked up
+/db
+/output_files
+/incremental_db
+/greybox_tmp
+/work
+/altera

+ 44 - 8
Makefile

@@ -1,24 +1,60 @@
-QUARTUS_ROOT := C:/intelFPGA_lite/20.1
-QUARTUS_DIR = ${QUARTUS_ROOT}/quartus
-MODELSIM_DIR = ${QUARTUS_ROOT}/modelsim_ase
+QUARTUS_ROOT := /opt/intelFPGA/* C:/intelFPGA_lite/*
+
+### Finding quartus dir. If not found, edit QUARTUS_ROOT above
+QUARTUS_ROOT_PATH = $(word 1, $(foreach dir, $(QUARTUS_ROOT), $(wildcard $(dir))))
+ifeq ($(QUARTUS_ROOT_PATH),)
+$(error Failed to find Quartus installation dir, change QUARTUS_ROOT parameter)
+endif
+
+### Finding needed binary files
+QUARTUS_SH = $(word 1, $(wildcard $(QUARTUS_ROOT_PATH)/quartus/*/quartus_sh))
+QUARTUS_MAP = $(word 1, $(wildcard $(QUARTUS_ROOT_PATH)/quartus/*/quartus_map))
+MODELSIM_BIN = $(word 1, $(wildcard $(QUARTUS_ROOT_PATH)/modelsim_ase/*/vsim))
+
+### Checking if we have everything we need
+ifeq ($(QUARTUS_SH),)
+$(error Failed to find QUARTUS_SH)
+endif
+ifeq ($(QUARTUS_MAP),)
+$(error Failed to find QUARTUS_MAP)
+endif
+ifeq ($(MODELSIM_BIN),)
+$(error Failed to find MODELSIM_BIN)
+endif
+
+$(info QUARTUS_MAP=$(QUARTUS_MAP))
+$(info MODELSIM_BIN=$(MODELSIM_BIN))
+
+### Remaining configurations
 PROJECT_NAME = altera_devel
-MODELSIM_GUI = ${QUARTUS_DIR}/bin64/quartus_sh -t "${QUARTUS_DIR}/common/tcl/internal/nativelink/qnativesim.tcl" --rtl_sim "${PROJECT_NAME}" "${PROJECT_NAME}"
-MODELSIM_BIN = ${MODELSIM_DIR}/win32aloem/vsim
-QUARTUS_MACROS =  --set VERILOG_MACRO="SYNTHESIS=1"
+QUARTUS_MACROS = --set VERILOG_MACRO="SYNTHESIS=1"
 VSIM_ARGS = -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -voptargs="+acc"
 
+
+### Optional parameters
 tb_file ?=
 tb_dir = $(dirname "${testbench_file}")
 tb_mod ?=
+do_file ?=
+
+### ================================================================
+### Commands
+### ================================================================
 
 analysis:
-	${QUARTUS_DIR}/bin64/quartus_map --read_settings_files=on --write_settings_files=off ${QUARTUS_MACROS} ${PROJECT_NAME} -c ${PROJECT_NAME} --analysis_and_elaboration
+	${QUARTUS_MAP} --read_settings_files=on --write_settings_files=off ${QUARTUS_MACROS} ${PROJECT_NAME} -c ${PROJECT_NAME} --analysis_and_elaboration
 
 modelsim: analysis
-	${MODELSIM_GUI}
+	${QUARTUS_SH} -t "${QUARTUS_ROOT_PATH}/quartus/common/tcl/internal/nativelink/qnativesim.tcl" --rtl_sim "${PROJECT_NAME}" "${PROJECT_NAME}"
 
 modelsim_cli:
 	${MODELSIM_BIN} -c
 
+sim:
+	cd ./simulation/modelsim && ${MODELSIM_BIN} -c -do "${do_file}"
+
+sim_gui:
+	cd ./simulation/modelsim && ${MODELSIM_BIN} -gui -do "${do_file}"
+
 testbench:
 	${MODELSIM_BIN} -c -do "vlog -sv +incdir+${tb_dir} {${tb_file}}; vsim -t 1ps ${VSIM_ARGS} ${tb_mod}; run -all"

+ 37 - 6
altera_devel.qsf

@@ -42,21 +42,52 @@ set_global_assignment -name DEVICE EP4CE22F17C6
 set_global_assignment -name TOP_LEVEL_ENTITY root
 set_global_assignment -name ORIGINAL_QUARTUS_VERSION 20.1.0
 set_global_assignment -name PROJECT_CREATION_TIME_DATE "11:51:52  OCTOBER 03, 2020"
-set_global_assignment -name LAST_QUARTUS_VERSION "20.1.0 Lite Edition"
+set_global_assignment -name LAST_QUARTUS_VERSION "20.1.1 Lite Edition"
 set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
 set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
 set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
 set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
 set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
-set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (Verilog)"
+set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (SystemVerilog)"
 set_global_assignment -name EDA_TIME_SCALE "1 ps" -section_id eda_simulation
-set_global_assignment -name EDA_OUTPUT_DATA_FORMAT "VERILOG HDL" -section_id eda_simulation
+set_global_assignment -name EDA_OUTPUT_DATA_FORMAT "SYSTEMVERILOG HDL" -section_id eda_simulation
 set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_timing
 set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_symbol
 set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_signal_integrity
 set_global_assignment -name EDA_GENERATE_FUNCTIONAL_NETLIST OFF -section_id eda_board_design_boundary_scan
-set_global_assignment -name SYSTEMVERILOG_FILE src/root.sv
-set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
 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 PARTITION_COLOR 16764057 -section_id Top
+set_location_assignment PIN_R8 -to clk
+set_location_assignment PIN_E1 -to keys[1]
+set_location_assignment PIN_J15 -to keys[0]
+set_location_assignment PIN_L3 -to leds[7]
+set_location_assignment PIN_B1 -to leds[6]
+set_location_assignment PIN_F3 -to leds[5]
+set_location_assignment PIN_A15 -to leds[0]
+set_location_assignment PIN_A13 -to leds[1]
+set_location_assignment PIN_B13 -to leds[2]
+set_location_assignment PIN_A11 -to leds[3]
+set_location_assignment PIN_D1 -to leds[4]
+set_location_assignment PIN_M1 -to switches[0]
+set_location_assignment PIN_T8 -to switches[1]
+set_location_assignment PIN_B9 -to switches[2]
+set_location_assignment PIN_M15 -to switches[3]
+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 SYSTEMVERILOG_FILE src/fpu32/fpu32.sv
+set_global_assignment -name SYSTEMVERILOG_FILE src/root.sv
+set_global_assignment -name QIP_FILE src/fpu32/fpu_add.qip
+set_global_assignment -name QIP_FILE src/fpu32/fpu_div.qip
+set_global_assignment -name QIP_FILE src/fpu32/fpu_mul.qip
+set_global_assignment -name QIP_FILE src/blocks/pll.qip
+set_global_assignment -name EDA_TEST_BENCH_ENABLE_STATUS TEST_BENCH_MODE -section_id eda_simulation
+set_global_assignment -name EDA_NATIVELINK_SIMULATION_TEST_BENCH root_tb -section_id eda_simulation
+set_global_assignment -name EDA_TEST_BENCH_NAME root_tb -section_id eda_simulation
+set_global_assignment -name EDA_DESIGN_INSTANCE_NAME NA -section_id root_tb
+set_global_assignment -name EDA_TEST_BENCH_MODULE_NAME fpu32_tb -section_id root_tb
+set_global_assignment -name SOURCE_FILE db/altera_devel.cmp.rdb
+set_global_assignment -name EDA_TEST_BENCH_FILE src/root.sv -section_id root_tb
+set_global_assignment -name EDA_TEST_BENCH_FILE src/fpu32/fpu32.sv -section_id root_tb
+set_global_assignment -name QIP_FILE altera/fpu32_adder.qip
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

+ 19 - 2
readme.md

@@ -1,16 +1,33 @@
 # Altera Development Repo
 
 ### Setup
+Just run analysis
+```bash
+make analysis
+```
+if not working, specify Quartus installation directory with **QUARTUS_ROOT** parameter
+
 Start modelsim GUI
 ```bash
 make modelsim
 ```
 
-### Running benchmarks
+### Running testbench
 
-This will run test benchmark in console without opening modelsim GUI
+This will run test testbench in console without opening modelsim GUI
 ```bash
 make tb_file=${file} tb_mod=${module} testbench
 # Example
 make tb_file=./src/root.sv tb_mod=root_tb testbench
+```
+Running testbench with defined simulation tcl script.
+Scripts has be located in **simulation/modelsim/sim_\*.do**
+```bash
+# With GUI
+make do_file=${file} sim_gui
+# Without GUI
+make do_file=${file} sim
+
+# Example
+make do_file=sim_root_tb.do sim_gui
 ```

+ 32 - 0
scripts/fpu_test_gen.py

@@ -0,0 +1,32 @@
+import numpy as np
+import os
+
+def generate_fp_vector(cases, filename, dtype=np.float16):
+    dsize = 0
+    if dtype == np.float16:
+        dsize = 2
+    elif dtype == np.float32:
+        dsize = 4
+    else:
+        raise ValueError(f"Unknown dtype {dtype}")
+
+    x = np.frombuffer(os.urandom(cases * dsize), dtype=dtype)
+    y = np.frombuffer(os.urandom(cases * dsize), dtype=dtype)
+    sum = x + y
+    mul = x * y
+    x = x.tobytes()
+    y = y.tobytes()
+    sum = sum.tobytes()
+    mul = mul.tobytes()
+    with open(filename, 'w') as f:
+        for i in range(cases):
+            f.write(' '.join([
+                x[i*dsize:i*dsize+dsize].hex(),
+                y[i*dsize:i*dsize+dsize].hex(),
+                sum[i*dsize:i*dsize+dsize].hex(),
+                mul[i*dsize:i*dsize+dsize].hex(),
+            ]) + '\n')
+
+
+if __name__ == '__main__':
+    generate_fp_vector(30, 'fp32_test.hex', dtype=np.float32)

+ 20 - 0
simulation/modelsim/sim_fpu32.do

@@ -0,0 +1,20 @@
+#transcript on
+if {[file exists rtl_work]} {
+	vdel -lib rtl_work -all
+}
+set rootdir [pwd]/../..
+puts "Root Directory $rootdir"
+vlib rtl_work
+vmap work rtl_work
+
+vlog -sv -work work +incdir+${rootdir}/src ${rootdir}/src/fpu32/fpu32.sv
+vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L rtl_work -L work -voptargs="+acc" fpu32_tb
+
+view structure
+view signals
+
+add wave -noupdate -label CLK /fpu32_tb/clk
+add wave -noupdate -label RESET /fpu32_tb/reset
+add wave -noupdate -label INPUT_A -radix float32 /fpu32_tb/input_a
+add wave -noupdate -label INPUT_B -radix float32 /fpu32_tb/input_b
+add wave -noupdate -label RESULT_ADDER -radix float32 /fpu32_tb/result_add

+ 44 - 0
simulation/modelsim/sim_root_tb.do

@@ -0,0 +1,44 @@
+#transcript on
+if {[file exists rtl_work]} {
+	vdel -lib rtl_work -all
+}
+set rootdir [pwd]/../..
+puts "Root Directory $rootdir"
+vlib rtl_work
+vmap work rtl_work
+
+vlog -vlog01compat -work work +incdir+${rootdir}/src/blocks ${rootdir}/src/blocks/pll.v
+vlog -vlog01compat -work work +incdir+${rootdir}/db ${rootdir}/db/pll_altpll.v
+vlog -sv -work work +incdir+${rootdir}/src ${rootdir}/src/root.sv
+vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L rtl_work -L work -voptargs="+acc"  root_tb
+
+view structure
+view signals
+
+add wave -position end -label CLK50 sim:/root_tb/CLK50
+add wave -position end -label MCLK  sim:/root_tb/de0nano_0/mclk
+add wave -position end -label RESET  sim:/root_tb/de0nano_0/reset
+add wave -position end -label KEYS  sim:/root_tb/KEYS
+add wave -position end -label LEDS  sim:/root_tb/LEDS
+add wave -position end -label SWITCHES  sim:/root_tb/SWITCHS
+
+TreeUpdate [SetDefaultTree]
+WaveRestoreCursors {{Cursor 1} {0 ps} 0}
+quietly wave cursor active 0
+configure wave -namecolwidth 150
+configure wave -valuecolwidth 100
+configure wave -justifyvalue left
+configure wave -signalnamewidth 0
+configure wave -snapdistance 10
+configure wave -datasetprefix 0
+configure wave -rowmargin 4
+configure wave -childrowmargin 2
+configure wave -gridoffset 0
+configure wave -gridperiod 1
+configure wave -griddelta 40
+configure wave -timeline 0
+configure wave -timelineunits ns
+update
+WaveRestoreZoom {0 ps} {1 ns}
+
+run 7000

+ 6 - 0
src/blocks/pll.qip

@@ -0,0 +1,6 @@
+set_global_assignment -name IP_TOOL_NAME "ALTPLL"
+set_global_assignment -name IP_TOOL_VERSION "20.1"
+set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}"
+set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_bb.v"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"]

+ 324 - 0
src/blocks/pll.v

@@ -0,0 +1,324 @@
+// megafunction wizard: %ALTPLL%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: altpll 
+
+// ============================================================
+// File Name: pll.v
+// Megafunction Name(s):
+// 			altpll
+//
+// Simulation Library Files(s):
+// 			altera_mf
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 20.1.0 Build 711 06/05/2020 SJ Lite Edition
+// ************************************************************
+
+
+//Copyright (C) 2020  Intel Corporation. All rights reserved.
+//Your use of Intel Corporation's design tools, logic functions 
+//and other software and tools, and any 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 Intel Program License 
+//Subscription Agreement, the Intel Quartus Prime License Agreement,
+//the Intel FPGA IP License Agreement, or other applicable license
+//agreement, including, without limitation, that your use is for
+//the sole purpose of programming logic devices manufactured by
+//Intel and sold by Intel or its authorized distributors.  Please
+//refer to the applicable agreement for further details, at
+//https://fpgasoftware.intel.com/eula.
+
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+module pll #(
+    parameter DIVIDER=20,
+    parameter MULTI=1
+) (
+	areset,
+	inclk0,
+	c0,
+	locked);
+
+	input	  areset;
+	input	  inclk0;
+	output	  c0;
+	output	  locked;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_off
+`endif
+	tri0	  areset;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_on
+`endif
+
+	wire [4:0] sub_wire0;
+	wire  sub_wire2;
+	wire [0:0] sub_wire5 = 1'h0;
+	wire [0:0] sub_wire1 = sub_wire0[0:0];
+	wire  c0 = sub_wire1;
+	wire  locked = sub_wire2;
+	wire  sub_wire3 = inclk0;
+	wire [1:0] sub_wire4 = {sub_wire5, sub_wire3};
+
+	altpll	altpll_component (
+				.areset (areset),
+				.inclk (sub_wire4),
+				.clk (sub_wire0),
+				.locked (sub_wire2),
+				.activeclock (),
+				.clkbad (),
+				.clkena ({6{1'b1}}),
+				.clkloss (),
+				.clkswitch (1'b0),
+				.configupdate (1'b0),
+				.enable0 (),
+				.enable1 (),
+				.extclk (),
+				.extclkena ({4{1'b1}}),
+				.fbin (1'b1),
+				.fbmimicbidir (),
+				.fbout (),
+				.fref (),
+				.icdrclk (),
+				.pfdena (1'b1),
+				.phasecounterselect ({4{1'b1}}),
+				.phasedone (),
+				.phasestep (1'b1),
+				.phaseupdown (1'b1),
+				.pllena (1'b1),
+				.scanaclr (1'b0),
+				.scanclk (1'b0),
+				.scanclkena (1'b1),
+				.scandata (1'b0),
+				.scandataout (),
+				.scandone (),
+				.scanread (1'b0),
+				.scanwrite (1'b0),
+				.sclkout0 (),
+				.sclkout1 (),
+				.vcooverrange (),
+				.vcounderrange ());
+	defparam
+		altpll_component.bandwidth_type = "AUTO",
+		altpll_component.clk0_divide_by = 20,
+		altpll_component.clk0_duty_cycle = 50,
+		altpll_component.clk0_multiply_by = 1,
+		altpll_component.clk0_phase_shift = "0",
+		altpll_component.compensate_clock = "CLK0",
+		altpll_component.inclk0_input_frequency = 5000,
+		altpll_component.intended_device_family = "Cyclone IV E",
+		altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll",
+		altpll_component.lpm_type = "altpll",
+		altpll_component.operation_mode = "NORMAL",
+		altpll_component.pll_type = "AUTO",
+		altpll_component.port_activeclock = "PORT_UNUSED",
+		altpll_component.port_areset = "PORT_USED",
+		altpll_component.port_clkbad0 = "PORT_UNUSED",
+		altpll_component.port_clkbad1 = "PORT_UNUSED",
+		altpll_component.port_clkloss = "PORT_UNUSED",
+		altpll_component.port_clkswitch = "PORT_UNUSED",
+		altpll_component.port_configupdate = "PORT_UNUSED",
+		altpll_component.port_fbin = "PORT_UNUSED",
+		altpll_component.port_inclk0 = "PORT_USED",
+		altpll_component.port_inclk1 = "PORT_UNUSED",
+		altpll_component.port_locked = "PORT_USED",
+		altpll_component.port_pfdena = "PORT_UNUSED",
+		altpll_component.port_phasecounterselect = "PORT_UNUSED",
+		altpll_component.port_phasedone = "PORT_UNUSED",
+		altpll_component.port_phasestep = "PORT_UNUSED",
+		altpll_component.port_phaseupdown = "PORT_UNUSED",
+		altpll_component.port_pllena = "PORT_UNUSED",
+		altpll_component.port_scanaclr = "PORT_UNUSED",
+		altpll_component.port_scanclk = "PORT_UNUSED",
+		altpll_component.port_scanclkena = "PORT_UNUSED",
+		altpll_component.port_scandata = "PORT_UNUSED",
+		altpll_component.port_scandataout = "PORT_UNUSED",
+		altpll_component.port_scandone = "PORT_UNUSED",
+		altpll_component.port_scanread = "PORT_UNUSED",
+		altpll_component.port_scanwrite = "PORT_UNUSED",
+		altpll_component.port_clk0 = "PORT_USED",
+		altpll_component.port_clk1 = "PORT_UNUSED",
+		altpll_component.port_clk2 = "PORT_UNUSED",
+		altpll_component.port_clk3 = "PORT_UNUSED",
+		altpll_component.port_clk4 = "PORT_UNUSED",
+		altpll_component.port_clk5 = "PORT_UNUSED",
+		altpll_component.port_clkena0 = "PORT_UNUSED",
+		altpll_component.port_clkena1 = "PORT_UNUSED",
+		altpll_component.port_clkena2 = "PORT_UNUSED",
+		altpll_component.port_clkena3 = "PORT_UNUSED",
+		altpll_component.port_clkena4 = "PORT_UNUSED",
+		altpll_component.port_clkena5 = "PORT_UNUSED",
+		altpll_component.port_extclk0 = "PORT_UNUSED",
+		altpll_component.port_extclk1 = "PORT_UNUSED",
+		altpll_component.port_extclk2 = "PORT_UNUSED",
+		altpll_component.port_extclk3 = "PORT_UNUSED",
+		altpll_component.self_reset_on_loss_lock = "OFF",
+		altpll_component.width_clock = 5;
+
+
+endmodule
+
+// ============================================================
+// 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 "c0"
+// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0"
+// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "6"
+// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1"
+// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000"
+// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "5.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 "100.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: MIG_DEVICE_SPEED_GRADE STRING "Any"
+// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0"
+// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1"
+// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1"
+// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "5.00000000"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 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 "0.00000000"
+// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0"
+// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg"
+// 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: 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_CLKENA0 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 "20"
+// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50"
+// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "1"
+// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0"
+// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0"
+// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "10000"
+// 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_UNUSED"
+// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED"
+// 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: 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: 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: locked 0 0 0 0 @locked 0 0 0 0
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v 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 FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v TRUE
+// Retrieval info: LIB_FILE: altera_mf
+// Retrieval info: CBX_MODULE_PREFIX: ON

+ 305 - 0
src/fpu32/adder.v

@@ -0,0 +1,305 @@
+//IEEE Floating Point Adder (Single Precision)
+//Copyright (C) Jonathan P Dawson 2013
+//2013-12-12
+
+module adder(
+        input_a,
+        input_b,
+        input_a_stb,
+        input_b_stb,
+        output_z_ack,
+        clk,
+        rst,
+        output_z,
+        output_z_stb,
+        input_a_ack,
+        input_b_ack);
+
+  input     clk;
+  input     rst;
+
+  input     [31:0] input_a;
+  input     input_a_stb;
+  output    input_a_ack;
+
+  input     [31:0] input_b;
+  input     input_b_stb;
+  output    input_b_ack;
+
+  output    [31:0] output_z;
+  output    output_z_stb;
+  input     output_z_ack;
+
+  reg       s_output_z_stb;
+  reg       [31:0] s_output_z;
+  reg       s_input_a_ack;
+  reg       s_input_b_ack;
+
+  reg       [3:0] state;
+  parameter get_a         = 4'd0,
+            get_b         = 4'd1,
+            unpack        = 4'd2,
+            special_cases = 4'd3,
+            align         = 4'd4,
+            add_0         = 4'd5,
+            add_1         = 4'd6,
+            normalise_1   = 4'd7,
+            normalise_2   = 4'd8,
+            round         = 4'd9,
+            pack          = 4'd10,
+            put_z         = 4'd11,
+            get_input     = 4'd12;
+
+  reg       [31:0] a, b, z;
+  reg       [26:0] a_m, b_m;
+  reg       [23:0] z_m;
+  reg       [9:0] a_e, b_e, z_e;
+  reg       a_s, b_s, z_s;
+  reg       guard, round_bit, sticky;
+  reg       [27:0] sum;
+
+  always @(posedge clk)
+  begin
+
+    case(state)
+
+      get_a:
+      begin
+        s_input_a_ack <= 1;
+        if (s_input_a_ack && input_a_stb) begin
+          a <= input_a;
+          s_input_a_ack <= 0;
+          state <= get_b;
+        end
+      end
+
+      get_input:
+      begin
+        s_input_a_ack <= 1;
+        s_input_b_ack <= 1;
+        if (s_input_a_ack && input_a_stb && s_input_b_ack && input_b_stb) begin
+          a <= input_a;
+          b <= input_b;
+          s_input_a_ack <= 0;
+          s_input_b_ack <= 0;
+          state <= unpack;
+        end
+      end
+
+      get_b:
+      begin
+        s_input_b_ack <= 1;
+        if (s_input_b_ack && input_b_stb) begin
+          b <= input_b;
+          s_input_b_ack <= 0;
+          state <= unpack;
+        end
+      end
+
+      unpack:
+      begin
+        a_m <= {a[22 : 0], 3'd0};
+        b_m <= {b[22 : 0], 3'd0};
+        a_e <= a[30 : 23] - 127;
+        b_e <= b[30 : 23] - 127;
+        a_s <= a[31];
+        b_s <= b[31];
+        state <= special_cases;
+      end
+
+      special_cases:
+      begin
+        //if a is NaN or b is NaN return NaN
+        if ((a_e == 128 && a_m != 0) || (b_e == 128 && b_m != 0)) begin
+          z[31] <= 1;
+          z[30:23] <= 255;
+          z[22] <= 1;
+          z[21:0] <= 0;
+          state <= put_z;
+        //if a is inf return inf
+        end else if (a_e == 128) begin
+          z[31] <= a_s;
+          z[30:23] <= 255;
+          z[22:0] <= 0;
+          //if a is inf and signs don't match return nan
+          if ((b_e == 128) && (a_s != b_s)) begin
+              z[31] <= b_s;
+              z[30:23] <= 255;
+              z[22] <= 1;
+              z[21:0] <= 0;
+          end
+          state <= put_z;
+        //if b is inf return inf
+        end else if (b_e == 128) begin
+          z[31] <= b_s;
+          z[30:23] <= 255;
+          z[22:0] <= 0;
+          state <= put_z;
+        //if a is zero return b
+        end else if ((($signed(a_e) == -127) && (a_m == 0)) && (($signed(b_e) == -127) && (b_m == 0))) begin
+          z[31] <= a_s & b_s;
+          z[30:23] <= b_e[7:0] + 127;
+          z[22:0] <= b_m[26:3];
+          state <= put_z;
+        //if a is zero return b
+        end else if (($signed(a_e) == -127) && (a_m == 0)) begin
+          z[31] <= b_s;
+          z[30:23] <= b_e[7:0] + 127;
+          z[22:0] <= b_m[26:3];
+          state <= put_z;
+        //if b is zero return a
+        end else if (($signed(b_e) == -127) && (b_m == 0)) begin
+          z[31] <= a_s;
+          z[30:23] <= a_e[7:0] + 127;
+          z[22:0] <= a_m[26:3];
+          state <= put_z;
+        end else begin
+          //Denormalised Number
+          if ($signed(a_e) == -127) begin
+            a_e <= -126;
+          end else begin
+            a_m[26] <= 1;
+          end
+          //Denormalised Number
+          if ($signed(b_e) == -127) begin
+            b_e <= -126;
+          end else begin
+            b_m[26] <= 1;
+          end
+          state <= align;
+        end
+      end
+
+      align:
+      begin
+        if ($signed(a_e) > $signed(b_e)) begin
+          b_e <= b_e + 1;
+          b_m <= b_m >> 1;
+          b_m[0] <= b_m[0] | b_m[1];
+        end else if ($signed(a_e) < $signed(b_e)) begin
+          a_e <= a_e + 1;
+          a_m <= a_m >> 1;
+          a_m[0] <= a_m[0] | a_m[1];
+        end else begin
+          state <= add_0;
+        end
+      end
+
+      add_0:
+      begin
+        z_e <= a_e;
+        if (a_s == b_s) begin
+          sum <= a_m + b_m;
+          z_s <= a_s;
+        end else begin
+          if (a_m >= b_m) begin
+            sum <= a_m - b_m;
+            z_s <= a_s;
+          end else begin
+            sum <= b_m - a_m;
+            z_s <= b_s;
+          end
+        end
+        state <= add_1;
+      end
+
+      add_1:
+      begin
+        if (sum[27]) begin
+          z_m <= sum[27:4];
+          guard <= sum[3];
+          round_bit <= sum[2];
+          sticky <= sum[1] | sum[0];
+          z_e <= z_e + 1;
+        end else begin
+          z_m <= sum[26:3];
+          guard <= sum[2];
+          round_bit <= sum[1];
+          sticky <= sum[0];
+        end
+        state <= normalise_1;
+      end
+
+      normalise_1:
+      begin
+        if (z_m[23] == 0 && $signed(z_e) > -126) begin
+          z_e <= z_e - 1;
+          z_m <= z_m << 1;
+          z_m[0] <= guard;
+          guard <= round_bit;
+          round_bit <= 0;
+        end else begin
+          state <= normalise_2;
+        end
+      end
+
+      normalise_2:
+      begin
+        if ($signed(z_e) < -126) begin
+          z_e <= z_e + 1;
+          z_m <= z_m >> 1;
+          guard <= z_m[0];
+          round_bit <= guard;
+          sticky <= sticky | round_bit;
+        end else begin
+          state <= round;
+        end
+      end
+
+      round:
+      begin
+        if (guard && (round_bit | sticky | z_m[0])) begin
+          z_m <= z_m + 1;
+          if (z_m == 24'hffffff) begin
+            z_e <=z_e + 1;
+          end
+        end
+        state <= pack;
+      end
+
+      pack:
+      begin
+        z[22 : 0] <= z_m[22:0];
+        z[30 : 23] <= z_e[7:0] + 127;
+        z[31] <= z_s;
+        if ($signed(z_e) == -126 && z_m[23] == 0) begin
+          z[30 : 23] <= 0;
+        end
+        if ($signed(z_e) == -126 && z_m[23:0] == 24'h0) begin
+          z[31] <= 1'b0; // FIX SIGN BUG: -a + a = +0.
+        end
+        //if overflow occurs, return inf
+        if ($signed(z_e) > 127) begin
+          z[22 : 0] <= 0;
+          z[30 : 23] <= 255;
+          z[31] <= z_s;
+        end
+        state <= put_z;
+      end
+
+      put_z:
+      begin
+        s_output_z_stb <= 1;
+        s_output_z <= z;
+        if (s_output_z_stb && output_z_ack) begin
+          s_output_z_stb <= 0;
+          state <= get_input;
+        end
+      end
+
+    endcase
+
+    if (rst == 1) begin
+      state <= get_input;
+      s_input_a_ack <= 0;
+      s_input_b_ack <= 0;
+      s_output_z_stb <= 0;
+    end
+
+  end
+  assign input_a_ack = s_input_a_ack;
+  assign input_b_ack = s_input_b_ack;
+  assign output_z_stb = s_output_z_stb;
+  assign output_z = s_output_z;
+
+endmodule

+ 177 - 0
src/fpu32/adder_piped.v

@@ -0,0 +1,177 @@
+
+
+module adder_piped(
+    input wire reset, clk,
+    input [31:0] input_a, input_b,
+    output [31:0] output_z
+);
+
+// ========================
+// Stage 0
+// ========================
+reg [26:0] s0_a_m, s0_b_m;  // Matissa
+reg [9:0] s0_a_e, s0_b_e;   // Exponent
+reg s0_a_s, s0_b_s;         // Sign
+
+always @(posedge clk) begin
+    s0_a_m <= {input_a[22 : 0], 3'd0};
+    s0_b_m <= {input_b[22 : 0], 3'd0};
+    s0_a_e <= input_a[30 : 23] - 127;
+    s0_b_e <= input_b[30 : 23] - 127;
+    s0_a_s <= input_a[31];
+    s0_b_s <= input_b[31];
+end
+
+// ========================
+// Stage 1
+// ========================
+reg [26:0] s1_a_m, s1_b_m;  // Matissa
+reg [9:0] s1_a_e, s1_b_e;   // Exponent
+reg s1_a_s, s1_b_s;         // Sign
+reg [31:0] s1_z;
+reg s1_sp;  // Special case flag
+
+always @(posedge clk) begin
+    //if a is NaN or b is NaN return NaN
+    if ((s0_a_e == 128 && s0_a_m != 0) || (s0_b_e == 128 && s0_b_m != 0)) begin
+        s1_z[31] <= 1;
+        s1_z[30:23] <= 255;
+        s1_z[22] <= 1;
+        s1_z[21:0] <= 0;
+        s1_sp <= 1;
+    //if a is inf return inf
+    end else if (s0_a_e == 128) begin
+        s1_z[31] <= s0_a_s;
+        s1_z[30:23] <= 255;
+        s1_z[22:0] <= 0;
+        //if a is inf and signs don't match return nan
+        if ((s0_b_e == 128) && (s0_a_s != s0_b_s)) begin
+            s1_z[31] <= s0_b_s;
+            s1_z[30:23] <= 255;
+            s1_z[22] <= 1;
+            s1_z[21:0] <= 0;
+        end
+        s1_sp <= 1;
+    //if b is inf return inf
+    end else if (s0_b_e == 128) begin
+        s1_z[31] <= s0_b_s;
+        s1_z[30:23] <= 255;
+        s1_z[22:0] <= 0;
+        s1_sp <= 1;
+    //if a is zero return b
+    end else if ((($signed(s0_a_e) == -127) && (s0_a_m == 0)) && (($signed(s0_b_e) == -127) && (s0_b_m == 0))) begin
+        s1_z[31] <= s0_a_s & s0_b_s;
+        s1_z[30:23] <= s0_b_e[7:0] + 127;
+        s1_z[22:0] <= s0_b_m[26:3];
+        s1_sp <= 1;
+    //if a is zero return b
+    end else if (($signed(s0_a_e) == -127) && (s0_a_m == 0)) begin
+        s1_z[31] <= s0_b_s;
+        s1_z[30:23] <= s0_b_e[7:0] + 127;
+        s1_z[22:0] <= s0_b_m[26:3];
+        s1_sp <= 1;
+    //if b is zero return a
+    end else if (($signed(s0_b_e) == -127) && (s0_b_m == 0)) begin
+        s1_z[31] <= s0_a_s;
+        s1_z[30:23] <= s0_a_e[7:0] + 127;
+        s1_z[22:0] <= s0_a_m[26:3];
+        s1_sp <= 1;
+    end else begin
+        //Denormalised Number
+        if ($signed(s0_a_e) == -127) begin
+            s1_a_e <= -126;
+            s1_a_m <= s0_a_m;
+        end else begin
+            s1_a_e <= s0_a_e;
+            s1_a_m[26] <= {1, s0_a_m[27:0]};
+        end
+        //Denormalised Number
+        if ($signed(s0_b_e) == -127) begin
+            s1_b_e <= -126;
+            s1_b_m <= s0_b_m;
+        end else begin
+            s1_b_e <= s0_b_e;
+            s1_b_m[26] <= {1, s0_a_m[27:0]};
+        end
+        s1_a_s <= s0_a_s;
+        s1_b_s <= s0_b_s; 
+        s1_sp <= 0;
+    end
+end
+
+// ========================
+// Stage 2
+// ========================
+reg [26:0] s2_a_m, s2_b_m;  // Matissa
+reg [9:0] s2_a_e, s2_b_e;   // Exponent
+reg s2_a_s, s2_b_s;         // Sign
+reg [31:0] s2_z;
+reg s2_sp;  // Special case flag
+
+wire [9:0] s2_comp;
+
+always @(posedge clk) begin
+    s2_z <= s1_z;
+    s2_sp <= s1_sp;
+end
+
+always @(posedge clk) begin
+    if ($signed(s1_a_e) > $signed(s1_b_e)) begin
+        s2_comp = $signed(s1_a_e) - $signed(s1_b_e);
+        s2_b_e <= s1_b_e + s2_comp;
+        s2_b_m <= s1_b_m >> s2_comp;
+        s2_b_m[0] <= s1_b_m[0] | s1_b_m[1];  // TODO: FIX
+        s2_a_e <= s1_a_e;
+        s2_a_m <= s1_a_m;
+    end else if ($signed(s1_a_e) < $signed(s1_b_e)) begin
+        s2_comp = $signed(s1_b_e) - $signed(s1_a_e);
+        s2_a_e <= s1_a_e + s2_comp;
+        s2_a_m <= s1_a_m >> s2_comp;
+        s2_a_m[0] <= s1_a_m[0] | s1_a_m[1];  // TODO: FIX
+        s2_b_e <= s1_b_e;
+        s2_b_m <= s1_b_m;
+    end else begin
+        s2_a_e <= s1_a_e;
+        s2_a_m <= s1_a_m;
+        s2_b_e <= s1_b_e;
+        s2_b_m <= s1_b_m;
+    end
+    s2_a_s <= s1_a_s;
+    s2_b_s <= s1_b_s;
+end
+
+
+// ========================
+// Stage 3
+// ========================
+reg [26:0] s3_a_m, s3_b_m;  // Matissa
+reg [9:0] s3_a_e, s3_b_e;   // Exponent
+reg s3_a_s, s3_b_s;         // Sign
+reg [31:0] s3_z;
+reg s3_sp;  // Special case flag
+
+wire [9:0] s3_comp;
+
+always @(posedge clk) begin
+    s3_z <= s2_z;
+    s3_sp <= s2_sp;
+end
+
+always @(posedge clk) begin
+    z_e <= a_e;
+    if (a_s == b_s) begin
+        sum <= a_m + b_m;
+        z_s <= a_s;
+    end else begin
+        if (a_m >= b_m) begin
+            sum <= a_m - b_m;
+            z_s <= a_s;
+        end else begin
+            sum <= b_m - a_m;
+            z_s <= b_s;
+        end
+    end
+end
+
+
+endmodule

+ 78 - 0
src/fpu32/fpu32.sv

@@ -0,0 +1,78 @@
+`include "adder.v"
+`include "mult.v"
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+
+module fpu32_tb();
+    reg reset, clk;
+    reg [31:0] input_a, input_b, result_add, result_div, result_mul;
+    wire nan, overflow, underflow, zero;
+
+
+    reg adder_input_a_stb, adder_input_b_stb, adder_output_z_ack;
+    wire adder_input_a_ack, adder_input_b_ack, adder_output_z_stb;
+
+	adder add0(
+	    .clk(clk),
+	    .rst(reset),
+	    .input_a(input_a),
+	    .input_a_stb(adder_input_a_stb),
+	    .input_a_ack(adder_input_a_ack),
+	    .input_b(input_b),
+	    .input_b_stb(adder_input_b_stb),
+	    .input_b_ack(adder_input_b_ack),
+	    .output_z(result_add),
+	    .output_z_ack(adder_output_z_ack),
+	    .output_z_stb(adder_output_z_stb)
+	);
+
+
+    initial forever #5 clk = ~clk;
+
+    reg [31:0] test_mem [29:0][3:0];
+
+    initial $readmemh("../../scripts/fp32_test.hex", test_mem);
+
+    initial begin
+        clk = 0;
+        reset = 1;
+        adder_input_a_stb = 0;
+        adder_input_b_stb = 0;
+        adder_output_z_ack = 0;
+
+        #20;
+        reset = 0;
+
+        foreach(test_mem[i]) begin
+            input_a = test_mem[i][0];
+            input_b = test_mem[i][1];
+            adder_input_a_stb = 1;
+            adder_input_b_stb = 1;
+
+            wait(adder_input_a_ack | adder_input_b_ack == 1);
+            #15;
+            adder_input_a_stb = 0;
+            adder_input_b_stb = 0;
+
+            @(posedge adder_output_z_stb);
+            adder_output_z_ack = 1;
+            if(result_add != test_mem[i][3])
+                $display("PASS: %H + %H = %H", input_a, input_b, result_add);
+            else
+                $error("FAIL ADD: %H + %H = %H, expected %H", input_a, input_b, result_add, test_mem[i][3]);
+
+            @(negedge adder_output_z_stb);
+            adder_output_z_ack = 0;
+            #10;
+        end
+
+//        assert(result_add == 32'h42440000);
+//        assert(result_mul == 32'hc2480000);
+//        $finish();
+//        test_inputs(32'h42480000, 32'hbf800000, 32'h42440000, 32'hc2480000, 32'hc2480000);
+    end
+
+
+endmodule : fpu32_tb

+ 276 - 0
src/fpu32/mult.v

@@ -0,0 +1,276 @@
+//IEEE Floating Point Multiplier (Single Precision)
+//Copyright (C) Jonathan P Dawson 2013
+//2013-12-12
+
+module multiplier(
+        input_a,
+        input_b,
+        input_a_stb,
+        input_b_stb,
+        output_z_ack,
+        clk,
+        rst,
+        output_z,
+        output_z_stb,
+        input_a_ack,
+        input_b_ack);
+
+  input     clk;
+  input     rst;
+
+  input     [31:0] input_a;
+  input     input_a_stb;
+  output    input_a_ack;
+
+  input     [31:0] input_b;
+  input     input_b_stb;
+  output    input_b_ack;
+
+  output    [31:0] output_z;
+  output    output_z_stb;
+  input     output_z_ack;
+
+  reg       s_output_z_stb;
+  reg       [31:0] s_output_z;
+  reg       s_input_a_ack;
+  reg       s_input_b_ack;
+
+  reg       [3:0] state;
+  parameter get_a         = 4'd0,
+            get_b         = 4'd1,
+            unpack        = 4'd2,
+            special_cases = 4'd3,
+            normalise_a   = 4'd4,
+            normalise_b   = 4'd5,
+            multiply_0    = 4'd6,
+            multiply_1    = 4'd7,
+            normalise_1   = 4'd8,
+            normalise_2   = 4'd9,
+            round         = 4'd10,
+            pack          = 4'd11,
+            put_z         = 4'd12;
+
+  reg       [31:0] a, b, z;
+  reg       [23:0] a_m, b_m, z_m;
+  reg       [9:0] a_e, b_e, z_e;
+  reg       a_s, b_s, z_s;
+  reg       guard, round_bit, sticky;
+  reg       [49:0] product;
+
+  always @(posedge clk)
+  begin
+
+    case(state)
+
+      get_a:
+      begin
+        s_input_a_ack <= 1;
+        if (s_input_a_ack && input_a_stb) begin
+          a <= input_a;
+          s_input_a_ack <= 0;
+          state <= get_b;
+        end
+      end
+
+      get_b:
+      begin
+        s_input_b_ack <= 1;
+        if (s_input_b_ack && input_b_stb) begin
+          b <= input_b;
+          s_input_b_ack <= 0;
+          state <= unpack;
+        end
+      end
+
+      unpack:
+      begin
+        a_m <= a[22 : 0];
+        b_m <= b[22 : 0];
+        a_e <= a[30 : 23] - 127;
+        b_e <= b[30 : 23] - 127;
+        a_s <= a[31];
+        b_s <= b[31];
+        state <= special_cases;
+      end
+
+      special_cases:
+      begin
+        //if a is NaN or b is NaN return NaN
+        if ((a_e == 128 && a_m != 0) || (b_e == 128 && b_m != 0)) begin
+          z[31] <= 1;
+          z[30:23] <= 255;
+          z[22] <= 1;
+          z[21:0] <= 0;
+          state <= put_z;
+        //if a is inf return inf
+        end else if (a_e == 128) begin
+          z[31] <= a_s ^ b_s;
+          z[30:23] <= 255;
+          z[22:0] <= 0;
+          //if b is zero return NaN
+          if (($signed(b_e) == -127) && (b_m == 0)) begin
+            z[31] <= 1;
+            z[30:23] <= 255;
+            z[22] <= 1;
+            z[21:0] <= 0;
+          end
+          state <= put_z;
+        //if b is inf return inf
+        end else if (b_e == 128) begin
+          z[31] <= a_s ^ b_s;
+          z[30:23] <= 255;
+          z[22:0] <= 0;
+          //if a is zero return NaN
+          if (($signed(a_e) == -127) && (a_m == 0)) begin
+            z[31] <= 1;
+            z[30:23] <= 255;
+            z[22] <= 1;
+            z[21:0] <= 0;
+          end
+          state <= put_z;
+        //if a is zero return zero
+        end else if (($signed(a_e) == -127) && (a_m == 0)) begin
+          z[31] <= a_s ^ b_s;
+          z[30:23] <= 0;
+          z[22:0] <= 0;
+          state <= put_z;
+        //if b is zero return zero
+        end else if (($signed(b_e) == -127) && (b_m == 0)) begin
+          z[31] <= a_s ^ b_s;
+          z[30:23] <= 0;
+          z[22:0] <= 0;
+          state <= put_z;
+        end else begin
+          //Denormalised Number
+          if ($signed(a_e) == -127) begin
+            a_e <= -126;
+          end else begin
+            a_m[23] <= 1;
+          end
+          //Denormalised Number
+          if ($signed(b_e) == -127) begin
+            b_e <= -126;
+          end else begin
+            b_m[23] <= 1;
+          end
+          state <= normalise_a;
+        end
+      end
+
+      normalise_a:
+      begin
+        if (a_m[23]) begin
+          state <= normalise_b;
+        end else begin
+          a_m <= a_m << 1;
+          a_e <= a_e - 1;
+        end
+      end
+
+      normalise_b:
+      begin
+        if (b_m[23]) begin
+          state <= multiply_0;
+        end else begin
+          b_m <= b_m << 1;
+          b_e <= b_e - 1;
+        end
+      end
+
+      multiply_0:
+      begin
+        z_s <= a_s ^ b_s;
+        z_e <= a_e + b_e + 1;
+        product <= a_m * b_m * 4;
+        state <= multiply_1;
+      end
+
+      multiply_1:
+      begin
+        z_m <= product[49:26];
+        guard <= product[25];
+        round_bit <= product[24];
+        sticky <= (product[23:0] != 0);
+        state <= normalise_1;
+      end
+
+      normalise_1:
+      begin
+        if (z_m[23] == 0) begin
+          z_e <= z_e - 1;
+          z_m <= z_m << 1;
+          z_m[0] <= guard;
+          guard <= round_bit;
+          round_bit <= 0;
+        end else begin
+          state <= normalise_2;
+        end
+      end
+
+      normalise_2:
+      begin
+        if ($signed(z_e) < -126) begin
+          z_e <= z_e + 1;
+          z_m <= z_m >> 1;
+          guard <= z_m[0];
+          round_bit <= guard;
+          sticky <= sticky | round_bit;
+        end else begin
+          state <= round;
+        end
+      end
+
+      round:
+      begin
+        if (guard && (round_bit | sticky | z_m[0])) begin
+          z_m <= z_m + 1;
+          if (z_m == 24'hffffff) begin
+            z_e <=z_e + 1;
+          end
+        end
+        state <= pack;
+      end
+
+      pack:
+      begin
+        z[22 : 0] <= z_m[22:0];
+        z[30 : 23] <= z_e[7:0] + 127;
+        z[31] <= z_s;
+        if ($signed(z_e) == -126 && z_m[23] == 0) begin
+          z[30 : 23] <= 0;
+        end
+        //if overflow occurs, return inf
+        if ($signed(z_e) > 127) begin
+          z[22 : 0] <= 0;
+          z[30 : 23] <= 255;
+          z[31] <= z_s;
+        end
+        state <= put_z;
+      end
+
+      put_z:
+      begin
+        s_output_z_stb <= 1;
+        s_output_z <= z;
+        if (s_output_z_stb && output_z_ack) begin
+          s_output_z_stb <= 0;
+          state <= get_a;
+        end
+      end
+
+    endcase
+
+    if (rst == 1) begin
+      state <= get_a;
+      s_input_a_ack <= 0;
+      s_input_b_ack <= 0;
+      s_output_z_stb <= 0;
+    end
+
+  end
+  assign input_a_ack = s_input_a_ack;
+  assign input_b_ack = s_input_b_ack;
+  assign output_z_stb = s_output_z_stb;
+  assign output_z = s_output_z;
+
+endmodule

+ 42 - 29
src/root.sv

@@ -1,35 +1,48 @@
-`include "./FPA_module_test.sv"
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+
+module root(
+    input  clk,
+    input  [1:0] keys,
+    input  [3:0] switches,
+    output [7:0] leds
+);
+
+    wire reset;
+    wire mclk;  // Master clock for main logic
+    wire pll_lock;
+
+    assign reset = ~(keys[0] & pll_lock);
+    pll pll0(
+        .areset(~keys[0]),
+        .inclk0(clk),
+        .c0(mclk),
+        .locked(pll_lock)
+    );
 
-module root(input a, b, output c);
-	assign c = a & b;
 endmodule : root
 
 
-module root_tb();
-	logic a, b, c;
-	root root_test(
-		.a(a),
-		.b(b),
-		.c(c)
-	);
-
-	task test_inputs;
-		input in_a, in_b, expected_c;
-		a = in_a;
-		b = in_b;
-		#2ps;
-		if(c == expected_c) $display("PASS: a=%b b=%b c=%b", a,b,c);
-		else $error("FAIL: a=%b b=%b c=%b, expected c=%b", a,b,c,expected_c);
-		#2ps;
-	endtask : test_inputs
-
-	initial begin
-		test_inputs(0, 0, 0);
-		test_inputs(0, 1, 0);
-		test_inputs(1, 0, 0);
-		test_inputs(1, 1, 1);
-		test_inputs(1, 1, 0);
-		$finish();
-	end
+module root_tb ();
+    reg  CLK50;
+    reg  [1:0] KEYS;
+    wire [7:0] LEDS;
+    reg  [3:0] SWITCHS;
+
+    root de0nano_0 (CLK50, KEYS, SWITCHS, LEDS);
+
+	initial forever #10ps CLK50 = !CLK50;
+
+    initial begin
+        CLK50 = 0;
+        KEYS = 2'b00;  // Keys are pull up, starting with both being pressed
+        SWITCHS = 4'b0000;
+
+        #60ps;
+        KEYS = 2'b11; // Release keys
+        #7000ps;
+        $finish();
+    end
 
 endmodule : root_tb