Computer Laboratory

Course pages 2015–16

ECAD and Architecture Practical Classes

Optional Exercise 1b: Shift register

Scheduling

If you finish Exercise 1 before the end of week 2 you can attempt this exercise. You should proceed to Exercise 2 if it is week 3 or later.

Outline

The display board attached to the DE1-SoC has a number of buttons and other inputs (see right).

Due to a lack of pins available between the display board and the DE1-SoC, these inputs are connected to a shift register that allows them to be read serially.

We use two 74HC165 shift register chips (data sheet). The schematic diagram shows how we have connected them in series. The shift register function table and internal schematic are shown separately. (Internals (c) NXP and TI datasheets)

Each button is active low (ie a push of the 'A' button causes BUTTON_A to go from high to low and then back to high again when released). The output of the shift register is inverted, so the bits received by the FPGA are active high (so we refer to BUTTON_A in the code).

In summary:

  • Taking SHIFTREG_LOADn will record the values of the buttons and store them in the shift register, replacing the current contents. This is an asynchronous load, in other words you should not change SHIFTREG_CLK while doing the load
  • A rising edge of SHIFTREG_CLK will cause the 16 bit contents to move one place to the right.
  • SHIFTREG_OUT will receive the (inverted) rightmost bit of the 16 bit contents into the FPGA.

Exercise

Write some Verilog to read the 16 inputs into the FPGA using the shift register.

Your code should have the following module interface

	module shiftregctl (
		input	clock_50m,
		input	reset,
		output	shiftreg_clk,
		output	shiftreg_loadn,
		input	shiftreg_out,
		output	[15:0] buttons
	);

		/* your code goes here */

	endmodule
		

Part 1

The standard clock clock_50 on the DE1-SoC board is 50MHz, or 20ns per cycle. The display board is connected via a ribbon cable which is not designed for propagation of high speed signals. Write a module that takes the 50MHz clock_50m and outputs an approximately 100KHz clock_100k (try dividing clock_50m by 512). Instantiate this inside your shiftregdriver.

Part 2

A simplified Verilog model of the shift register internals is as follows:

	module hc165 (
		input	logic loadn,
		input	logic clkinh,
		input	logic clk,
		input	logic ser,
		input	logic [7:0] d,
		output	logic q,
		output	logic qn
	);
		logic 	[7:0] state;
		logic	clk_enabled;

		always_ff @(posedge loadn)
			state <= d;
			
		always_ff @(posedge clk_enabled)
			state <= {state[6:0], ser };
			
		always_comb
		begin
			q = state[7];
			qn = !q;
			
			clk_enabled <= clk | clkinh;
		end
	endmodule
		

Note 1: this model isn't completely accurate because the real chip has state = d[7] (and thus q mirrors d[7]) all the time loadn is low, not just on its rising edge.

Note 2: it is generally bad style on FPGA to clock gate, that is to insert a gate in the path of the clock as we do with clk_enabled here. FPGAs have two separate networks for clock and logic respectively, and inserting logic after a clock implies that the clock must be routed over the logic network. This generally results in a lot of routing overhead and long propagation delays. In this case the external chip does this, and so we model that here. In your FPGA designs it is better not to use clock gating.

Write a state machine to clock out 16 bits from the shift register and store them in a 16 bit register buttons in the FPGA. This should use clock_100k as its primary clock, so that the external signals run at this lower speed. This state machine should run continuously, updating the buttons register with the most recent button values.

The following code with convert the buttons[15:0] into meaningful names:

typedef struct packed {
	logic button_b;
	logic button_a;
	logic button_y;
	logic button_x;
	logic spare0;
	logic touch_irq;
	logic spare1;
	logic spare2;
	logic nav_l;
	logic nav_r;
	logic nav_d;
	logic nav_u;
	logic nav_click;
	logic dialr_click;
	logic diall_click;
	logic temperature_alarm;
} buttonsT;

buttonsT buttons_decoded;

always_comb begin
	buttons_decoded = buttons;
	// access fields as eg buttons_decoded.dialr_click
end

Part 3

Write a testbench that instantiates a shiftregctl and two hc165 to model the whole system. Demonstrate that you can apply a 16 bit value to the inputs of the hc165s and that it appears on buttons.