The goal of this project is to demonstrate the capability of HLS in designing digital systems. For this purpose, I explain how to describe a digital clock in HLS. The NEXYS-4 evaluation board would be our target FPGA platform. If you are interested in learning HLS coding techniques please refer here or here.

The clock shows hours, minutes, and seconds on 7-segment displays.
It has two modes of operation: clock and setting. The clock mode is the standard mode during which the current time is shown on display. In the setting mode, you can use push-buttons to set the display clock.
The following figure shows the clock configuration on the board.

As shown in the following figure, the design has three main modules: one-second clock generator, digital clock engine and display driver.

The following pipelined loop is used to implement the one-second clock generator.
bool delay(long long int n) { #pragma HLS INLINE off static bool dummy = 0; for (long long int j = 0; j < n; j++) { #pragma HLS pipeline dummy = !dummy; } return dummy; } void one_second_clock_generator(bool &second) { #pragma HLS INTERFACE ap_none port=second #pragma HLS INTERFACE ap_ctrl_none port=return static bool s = 0; s=!s; second = s; delay(50000000L); }
The digital clock engine keeps track of hours, minutes and seconds and updates them when it receives a clock tick from the one-second clock generator module. The following code does this task.
void debounce(bool pulse, bool &out) { #pragma HLS INLINE off static bool out0 = 0; static bool out1 = 0; static bool out2 = 0; static bool state = 0; if (state == 0) { out2 = out1; out1 = out0; out0 = pulse; state = 1; } else { delay(2500000); state = 0; } out = out0 & out1 & out2; } void set_time( ap_uint<6> &seconds, ap_uint<6> &minutes, ap_uint<5> &hours, bool set_second, bool set_minute, bool set_hour) { //-------------------------------------------------- static bool second_state = 0; if (second_state == 0 && set_second == 1 ) { seconds++; if (seconds == 60) { seconds = 0; } second_state = 1; } if (second_state == 1 && set_second == 0 ) { second_state = 0; } //--------------------------------------------------- static bool minute_state = 0; if (minute_state == 0 && set_minute == 1 ) { minutes++; if (minutes == 60) { minutes = 0; } minute_state = 1; } if (minute_state == 1 && set_minute == 0 ) { minute_state = 0; } //---------------------------------------------------- static bool hour_state = 0; if (hour_state == 0 && set_hour == 1) { hours++; if (hours == 24) { hours = 0; } hour_state = 1; } if (hour_state == 1 && set_hour == 0) { hour_state = 0; } //---------------------------------------------------- } void clock_ticking( ap_uint<5> &hours, ap_uint<6> &minutes, ap_uint<6> &seconds) { seconds++; if (seconds == 60) { seconds = 0; minutes++; if (minutes == 60) { minutes = 0; hours++; if (hours == 24) hours = 0; } } } void digital_clock( bool set_time_sw, bool &set_time_led, bool set_second, bool set_minute, bool set_hour, bool one_second_delay, ap_uint<6> &seconds_out, ap_uint<6> &minutes_out, ap_uint<5> &hours_out ) { #pragma HLS INTERFACE ap_none port=set_time_sw #pragma HLS INTERFACE ap_none port=set_time_led #pragma HLS INTERFACE ap_none port=set_minute #pragma HLS INTERFACE ap_none port=set_hour #pragma HLS INTERFACE ap_none port=seconds_out #pragma HLS INTERFACE ap_none port=minutes_out #pragma HLS INTERFACE ap_none port=hours_out #pragma HLS INTERFACE ap_ctrl_none port=return static ap_uint<6> seconds = 0; static ap_uint<6> minutes = 0; static ap_uint<5> hours = 0; ap_uint<8> segment_data; ap_uint<8> segment_enable; static bool state_clock = 0; bool one_second = one_second_delay; bool set_time_flag = set_time_sw; if (one_second==1&&set_time_flag==0&&state_clock==0) { clock_ticking(hours, minutes, seconds); state_clock = 1; } if (one_second==0&&set_time_flag==0&&state_clock==1) { state_clock = 0; } if (set_time_flag == 1) { bool set_minute_debounce; bool set_hour_debounce; bool set_second_debounce; debounce (set_minute, set_minute_debounce); debounce (set_hour, set_hour_debounce); debounce (set_second, set_second_debounce); set_time(seconds, minutes, hours, set_second_debounce, set_minute_debounce, set_hour_debounce); } seconds_out = seconds; minutes_out = minutes; hours_out = hours; set_time_led = set_time_sw; }

And the last HLS code shows the current time on the 7-segment display.
#include <ap_int.h> const ap_uint<8> seven_segment_code[10] = { 0b11000000, 0b11111001, 0b10100100, 0b10110000, 0b10011001, 0b10010010, 0b10000010, 0b11111000, 0b10000000, 0b10010000 }; bool delay(long long int n) { #pragma HLS INLINE off static bool dummy = 0; for (long long int j = 0; j < n; j++) { #pragma HLS pipeline dummy = !dummy; } return dummy; } void seven_segment_display( ap_uint<5> hours, ap_uint<6> minutes, ap_uint<6> seconds, ap_uint<8> &seven_segment_data, ap_uint<8> &seven_segment_enable) { #pragma HLS INTERFACE ap_none port=hours #pragma HLS INTERFACE ap_none port=minutes #pragma HLS INTERFACE ap_none port=seconds #pragma HLS INTERFACE ap_none port=seven_segment_data #pragma HLS INTERFACE ap_none port=seven_segment_enable #pragma HLS INTERFACE ap_ctrl_none port=return ap_uint<4> second_digit_1 = seconds%10; ap_uint<4> second_digit_2 = seconds/10; ap_uint<4> minute_digit_1 = minutes%10; ap_uint<4> minute_digit_2 = minutes/10; ap_uint<4> hours_digit_1 = hours%10; ap_uint<4> hours_digit_2 = hours/10; ap_uint<8> segment_data; ap_uint<8> segment_enable; static ap_uint<3> state = 0; switch (state) { // second case 0: segment_data = seven_segment_code[second_digit_1]; segment_enable = 0b11111110; delay(250000L); state = 1; break; case 1: segment_data = seven_segment_code[second_digit_2]; segment_enable = 0b11111101; state = 2; delay(250000L); break; // minutes case 2: segment_data = seven_segment_code[minute_digit_1]; segment_enable = 0b11110111; state = 3; delay(250000L); break; case 3: segment_data = seven_segment_code[minute_digit_2]; segment_enable = 0b11101111; state = 4; delay(250000L); break; // hours case 4: segment_data = seven_segment_code[hours_digit_1]; segment_enable = 0b10111111; state = 5; delay(250000L); break; case 5: segment_data = seven_segment_code[hours_digit_2]; segment_enable = 0b01111111; state = 0; delay(250000L); break; default: segment_data = seven_segment_code[0]; segment_enable = 0b11111111; state = 0; delay(250000L); break; } seven_segment_data = segment_data; seven_segment_enable = segment_enable; }

After synthesising these codes, we should use the Xilinx Vivado toolset to connect them together and generate the FPGA bitstream.

After programming the board, you can test the design.
