aboutsummaryrefslogtreecommitdiff
path: root/src/verilog/novena_fmc_top.v
blob: 3b06b6f1ae20acc7b769c0a980efaca74151a8e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
`timescale 1ns / 1ps

module novena_fmc_top
	(
		input		wire 	       	gclk_p_pin,
		input		wire 	       	gclk_n_pin,

		input		wire 	       	reset_mcu_b_pin,
		
		input		wire				fmc_clk,		// clock
		input		wire	[21: 0]	fmc_a,		// address
		inout		wire	[31: 0]	fmc_d,		// data
		input		wire				fmc_ne1,		// chip select
		input		wire				fmc_noe,		// output enable
		input		wire				fmc_nwe,		// write enable
		input		wire				fmc_nl,		// latch enable
		output	wire				fmc_nwait,	// wait
		
		output	wire				apoptosis_pin,
		output	wire				led_pin
	);
	
	
		//
		// Clock Manager
		//
	wire	sys_clk;
	wire  sys_rst;

   novena_clkmgr_new #
	(
		.CLK_OUT_MUL	(2),	// 2..32
		.CLK_OUT_DIV	(2)	// 1..32
	)
	clkmgr
	(
		.gclk_p			(gclk_p_pin),
		.gclk_n			(gclk_n_pin),

		.reset_mcu_b	(reset_mcu_b_pin),

		.sys_clk			(sys_clk),
		.sys_rst			(sys_rst)
	);


		//
		// BUFG
		//
	wire	fmc_clk_bug;
	
   BUFG BUFG_fmc_clk
	(
		.I		(fmc_clk),
		.O		(fmc_clk_bufg)
	);
	
	
	
	//----------------------------------------------------------------
   // FMC Arbiter
   //
   // FMC arbiter handles FMC access and transfers it into
   // `sys_clk' clock domain.
   //----------------------------------------------------------------
	
	wire	[21: 0]	sys_fmc_addr;	// address
	wire				sys_fmc_wren;	// write enable
	wire				sys_fmc_rden;	// read enable
   wire	[31: 0]	sys_fmc_dout;	// data output (from STM32 to FPGA)
	reg	[31: 0]	sys_fmc_din;	// data input (from FPGA to STM32)
		
   fmc_arbiter #
	  (
	   .NUM_ADDR_BITS(22)	// change to 26 when 
	  )
	fmc
     (
		.fmc_clk(fmc_clk_bufg),
		.fmc_a(fmc_a),
		.fmc_d(fmc_d),
		.fmc_ne1(fmc_ne1),
		.fmc_nl(fmc_nl),
		.fmc_nwe(fmc_nwe),
		.fmc_noe(fmc_noe),
		.fmc_nwait(fmc_nwait),

      .sys_clk(sys_clk),

      .sys_addr(sys_fmc_addr),
      .sys_wr_en(sys_fmc_wren),
		.sys_rd_en(sys_fmc_rden),
      .sys_data_out(sys_fmc_dout),
      .sys_data_in(sys_fmc_din)
     );
				
		
	//----------------------------------------------------------------
	// Dummy Register
	//
	// General-purpose register to test FMC interface using STM32
	// demo program instead of core selector logic.
	//
	// This register is a bit tricky, but it allows testing of both
	// data and address buses. Reading from FPGA will always return
	// value, which is currently stored in the test register, 
	// regardless of read transaction address. Writing to FPGA has
	// two variants: a) writing to address 0 will store output data
	// data value in the test register, b) writing to any non-zero
	// address will store _address_ of write transaction in the test
	// register.
	//
	// To test data bus, write some different patterns to address 0,
	// then readback from any address and compare.
	//
	// To test address bus, write anything to some different non-zero
	// addresses, then readback from any address and compare returned
	// value with previously written address.
	//
	//----------------------------------------------------------------
	reg	[31: 0]	test_reg;
	
	always @(posedge sys_clk)
		//
		if (sys_fmc_wren) begin
			//
			// when writing to address 0, store input data value
			//
			// when writing to non-zero address, store _address_
			// (padded with zeroes) instead of data
			//
			test_reg <= (sys_fmc_addr == {22{1'b0}}) ? sys_fmc_dout : {{10{1'b0}}, sys_fmc_addr};
			//
		end else if (sys_fmc_rden) begin
			//
			// always return current value, ignore address
			//
			sys_fmc_din <= test_reg;
			//
		end
	
	
   //----------------------------------------------------------------
   // LED Driver
   //
   // A simple utility LED driver that turns on the Novena
   // board LED when the FMC interface is active.
   //----------------------------------------------------------------
   fmc_indicator led
     (
      .sys_clk(sys_clk),
      .sys_rst(sys_rst),
      .fmc_active(sys_fmc_wren | sys_fmc_rden),
      .led_out(led_pin)
      );
	
			
	//----------------------------------------------------------------
   // Novena Patch
   //
   // Patch logic to keep the Novena board happy.
   // The apoptosis_pin pin must be kept low or the whole board
   // (more exactly the CPU) will be reset after the FPGA has
   // been configured.
   //----------------------------------------------------------------
   assign apoptosis_pin = 1'b0;
	
	
endmodule