From 429d1ca34aeb0df444f557e86793dbdd1372ccce Mon Sep 17 00:00:00 2001 From: James McKenzie Date: Tue, 2 May 2023 10:57:51 +0100 Subject: working demo code for fpga board --- .gitignore | 4 + .gitmodules | 15 + Makefile | 64 ++++ src/.gitignore | 1 + src/abc | 1 + src/evb-yosys-demo/.gitignore | 7 + src/evb-yosys-demo/ice40-io-video/Makefile | 52 +++ src/evb-yosys-demo/ice40-io-video/example.v | 372 +++++++++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_0.v | 255 ++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_1.v | 263 +++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_2.v | 263 +++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_3.v | 277 +++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_4.v | 313 +++++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_5.v | 317 ++++++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_6.v | 364 ++++++++++++++++++++ src/evb-yosys-demo/ice40-io-video/example_7.v | 371 ++++++++++++++++++++ .../ice40-io-video/ice40-io-video.pcf | 14 + src/evb-yosys-demo/ice40hx8k-evb/.gitignore | 4 + src/evb-yosys-demo/ice40hx8k-evb/Makefile | 49 +++ src/evb-yosys-demo/ice40hx8k-evb/README | 6 + src/evb-yosys-demo/ice40hx8k-evb/example.v | 66 ++++ src/evb-yosys-demo/ice40hx8k-evb/ice40hx8k-evb.pcf | 5 + src/flashrom | 1 + src/icestorm | 1 + src/nextpnr | 1 + src/yosys | 1 + 26 files changed, 3087 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 src/.gitignore create mode 160000 src/abc create mode 100644 src/evb-yosys-demo/.gitignore create mode 100644 src/evb-yosys-demo/ice40-io-video/Makefile create mode 100644 src/evb-yosys-demo/ice40-io-video/example.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_0.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_1.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_2.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_3.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_4.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_5.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_6.v create mode 100644 src/evb-yosys-demo/ice40-io-video/example_7.v create mode 100644 src/evb-yosys-demo/ice40-io-video/ice40-io-video.pcf create mode 100644 src/evb-yosys-demo/ice40hx8k-evb/.gitignore create mode 100644 src/evb-yosys-demo/ice40hx8k-evb/Makefile create mode 100644 src/evb-yosys-demo/ice40hx8k-evb/README create mode 100644 src/evb-yosys-demo/ice40hx8k-evb/example.v create mode 100644 src/evb-yosys-demo/ice40hx8k-evb/ice40hx8k-evb.pcf create mode 160000 src/flashrom create mode 160000 src/icestorm create mode 160000 src/nextpnr create mode 160000 src/yosys diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f9860a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bin/ +sbin/ +share/ + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c86d273 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "src/yosys"] + path = src/yosys + url = https://github.com/YosysHQ/yosys +[submodule "src/nextpnr"] + path = src/nextpnr + url = https://github.com/YosysHQ/nextpnr +[submodule "src/icestorm"] + path = src/icestorm + url = https://github.com/YosysHQ/icestorm +[submodule "src/abc"] + path = src/abc + url = https://github.com/YosysHQ/abc +[submodule "src/flashrom"] + path = src/flashrom + url = https://github.com/flashrom/flashrom diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6104516 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +PREFIX=${PWD} + + +default:src/tools.stamp src/evb-yosys-demo.stamp + +src/evb-yosys-demo.stamp: src/tools.stamp + ${MAKE} -C src/evb-yosys-demo/ice40hx1k-evb + ${MAKE} -C src/evb-yosys-demo/ice40-io-video + touch $@ + +src/tools.stamp: src/nextpnr.stamp src/yosys.stamp src/flashrom.stamp + touch $@ + +src/yosys.stamp:#src/yosys/Makefile + # the muppets did not make this easy + if [ -d src/yosys/abc]; then ln -s ../abc src/yosys/abc; fi + (cd src/abc && rm -f .gitcommit && git checkout .gitcommit && git log -1 --pretty=format:"%h" > .gitcommit ) + ${MAKE} -C src/yosys PREFIX=${PREFIX} -j 16 + ${MAKE} -C src/yosys PREFIX=${PREFIX} install + (cd src/abc && rm -f .gitcommit && git checkout .gitcommit) + /bin/rm -f src/abc/abc-* + touch $@ + +#src/yosys/Makefile: +# git clone https://github.com/YosysHQ/yosys src/yosys + + +src/nextpnr.stamp: src/nextpnr/build/Makefile + ${MAKE} -C src/nextpnr/build + ${MAKE} -C src/nextpnr/build install + touch $@ + +src/nextpnr/build/Makefile:src/icestorm.stamp #src/nextpnr/CMakeLists.txt + mkdir -p src/nextpnr/build + (cd src/nextpnr/build && cmake .. -DARCH=ice40 -DICESTORM_INSTALL_PREFIX=${PREFIX} -DCMAKE_INSTALL_PREFIX=${PREFIX}) + + +#src/nextpnr/CMakeLists.tdxt: +# git clone https://github.com/YosysHQ/nextpnr src/nextpnr +# (cd src/nextpnr && git submodule init) +# (cd src/nextpnr && git submodule update) + + +src/icestorm.stamp: #src/icestorm/config.mk + ${MAKE} -C src/icestorm PREFIX=${PREFIX} + ${MAKE} -C src/icestorm PREFIX=${PREFIX} install + touch $@ + +src/flashrom.stamp: #src/flashrom/Makefile + ${MAKE} -C src/flashrom PREFIX=${PREFIX} + if [ -d src/flashrom/man8]; then ln -s ../abc src/flashrom/man8; fi + ${MAKE} -C src/flashrom PREFIX=${PREFIX} install + /bin/rm -f src/flashrom/man8 + touch $@ + + + + + + +#icestorm/config.mk: +# git clone https://github.com/YosysHQ/icestorm src/icestorm + + diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..ac5abaf --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +*.stamp diff --git a/src/abc b/src/abc new file mode 160000 index 0000000..2c1c83f --- /dev/null +++ b/src/abc @@ -0,0 +1 @@ +Subproject commit 2c1c83f75b8078ced51f92c697da3e712feb3ac3 diff --git a/src/evb-yosys-demo/.gitignore b/src/evb-yosys-demo/.gitignore new file mode 100644 index 0000000..d9ec733 --- /dev/null +++ b/src/evb-yosys-demo/.gitignore @@ -0,0 +1,7 @@ +*.json +*.asc +*.rpt +*.log +ice40-io-video/build/ +ice40hx1k-evb/build/ + diff --git a/src/evb-yosys-demo/ice40-io-video/Makefile b/src/evb-yosys-demo/ice40-io-video/Makefile new file mode 100644 index 0000000..8b5a9b1 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/Makefile @@ -0,0 +1,52 @@ +PREFIX=../../.. + +YOSYS=${PREFIX}/bin/yosys +NEXTPNR=${PREFIX}/bin/nextpnr-ice40 +ICEPACK=${PREFIX}/bin/icepack +ICETIME=${PREFIX}/bin/icetime +FLASH=${PREFIX}/bin/flash + +BUILDDIR = ./build +FPGA_TYPE = hx8k +FPGA_PKG = ct256 +PCF = ice40-io-video.pcf +RMDIR = rmdir + +# Targets +example: $(BUILDDIR)/example.rpt $(BUILDDIR)/example.bin +example_0: $(BUILDDIR)/example_0.rpt $(BUILDDIR)/example_0.bin +example_1: $(BUILDDIR)/example_1.rpt $(BUILDDIR)/example_1.bin +example_2: $(BUILDDIR)/example_2.rpt $(BUILDDIR)/example_2.bin +example_3: $(BUILDDIR)/example_3.rpt $(BUILDDIR)/example_3.bin +example_4: $(BUILDDIR)/example_4.rpt $(BUILDDIR)/example_4.bin +example_5: $(BUILDDIR)/example_5.rpt $(BUILDDIR)/example_5.bin +example_6: $(BUILDDIR)/example_6.rpt $(BUILDDIR)/example_6.bin +example_7: $(BUILDDIR)/example_7.rpt $(BUILDDIR)/example_7.bin + +flash: $(BUILDDIR)/example.bin + ${FLASH} ${BUILDDIR}/example.bin + + +$(BUILDDIR)/%.json: %.v + @mkdir -p $(@D) + ${YOSYS} -ql $(subst .json,,$@).log -p 'synth_ice40 -abc9 -device u -top top -json $@' $< + +%.asc: %.json + ${NEXTPNR} --${FPGA_TYPE} --package ${FPGA_PKG} --json $< --pcf ${PCF} --asc $@ + +%.bin: %.asc + ${ICEPACK} $< $@ + +%.rpt: %.asc + ${ICETIME} -d $(FPGA_TYPE) -mtr $@ $< + +all: example example_0 example_1 example_2 example_3 example_4 example_5 example_6 example_7 + +clean: + rm -f $(BUILDDIR)/*.asc $(BUILDDIR)/*.bin $(BUILDDIR)/*.rpt $(BUILDDIR)/*.log $(BUILDDIR)/*.json + $(RMDIR) $(BUILDDIR) + +# Uncomment this line if you want to keep the intermediate .json and .asc files +# .PRECIOUS: $(BUILDDIR)/%.json %.asc + +.PHONY: all prog clean example example_0 example_1 example_2 example_3 example_4 example_5 example_6 example_7 diff --git a/src/evb-yosys-demo/ice40-io-video/example.v b/src/evb-yosys-demo/ice40-io-video/example.v new file mode 100644 index 0000000..500aca6 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example.v @@ -0,0 +1,372 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +reg [20:0] arr_timer; // delay between key service + +reg [19:0] sq_figure [0:19]; + +wire [4:0] sq_fig_x; +wire [4:0] sq_fig_y; + +assign sq_fig_x = c_col - l_sq_pos_x; // our figure's x axis when in square boundary +assign sq_fig_y = c_row - u_sq_pos_y; // our figure's y axis when in square boundary + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + + + sq_figure[0][19:0] <= 20'b00000000000000000000; + sq_figure[1][19:0] <= 20'b00000001111100000000; + sq_figure[2][19:0] <= 20'b00000111111111000000; + sq_figure[3][19:0] <= 20'b00011111111111110000; + sq_figure[4][19:0] <= 20'b00111111111111111000; + sq_figure[5][19:0] <= 20'b00111111111111111000; + sq_figure[6][19:0] <= 20'b01111111111111111100; + sq_figure[7][19:0] <= 20'b01111111111111111100; + sq_figure[8][19:0] <= 20'b11111111111111111110; + sq_figure[9][19:0] <= 20'b11111111111111111110; + sq_figure[10][19:0] <= 20'b11111111111111111110; + sq_figure[11][19:0] <= 20'b11111111111111111110; + sq_figure[12][19:0] <= 20'b11111111111111111110; + sq_figure[13][19:0] <= 20'b01111111111111111100; + sq_figure[14][19:0] <= 20'b01111111111111111100; + sq_figure[15][19:0] <= 20'b00111111111111111000; + sq_figure[16][19:0] <= 20'b00111111111111111000; + sq_figure[17][19:0] <= 20'b00011111111111110000; + sq_figure[18][19:0] <= 20'b00000111111111000000; + sq_figure[19][19:0] <= 20'b00000001111100000000; + + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square + + //vga_r_r <= 7; + //vga_g_r <= 0; + //vga_b_r <= 7; + if(sq_figure[sq_fig_y][sq_fig_x] == 1) begin + vga_r_r <= 0; + vga_g_r <= 7; + vga_b_r <= 0; + end + else begin + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 7; + end + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + else begin + u_arr <= 0; + d_arr <= 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + else begin + d_arr <= 0; + u_arr <= 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + else begin + l_arr <= 0; + r_arr <= 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + else begin + r_arr <= 0; + l_arr <= 1; + end + end; + + end + + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + +/* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end +*/ + arr_timer <= arr_timer + 1; + + if(arr_timer == 0) begin + + sq_figure[8][19:0] <= sq_figure[8][19:0] ^ 20'b00000001111000000000; + sq_figure[9][19:0] <= sq_figure[9][19:0] ^ 20'b00000001111000000000; + sq_figure[10][19:0] <= sq_figure[10][19:0] ^ 20'b00000001111000000000; + sq_figure[11][19:0] <= sq_figure[11][19:0] ^ 20'b00000001111000000000; + + + if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + if(u_arr == 1) begin + u_arr <= 1; //0x75 up key + d_arr <= 0; + l_arr <= 0; + r_arr <= 0; + end + else begin + u_arr <= 1; //0x75 up key + d_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h6b) begin + if(l_arr == 1) begin + l_arr <= 1; //0x6B left key + r_arr <= 0; + u_arr <= 0; + d_arr <= 0; + end + else begin + l_arr <= 1; //0x6B left key + r_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h72) begin + if(d_arr == 1) begin + d_arr <= 1; //0x72 down key + u_arr <= 0; + l_arr <= 0; + r_arr <= 0; + end + else begin + d_arr <= 1; //0x72 down key + u_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h74) begin + if(r_arr == 1) begin + r_arr <= 1; //0x74 right key + l_arr <= 0; + u_arr <= 0; + d_arr <= 0; + end + else begin + r_arr <= 1; //0x74 right key + l_arr <= 0; + end + ps2_data_reg <= 0; + end + end + end + + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_0.v b/src/evb-yosys-demo/ice40-io-video/example_0.v new file mode 100644 index 0000000..23025e6 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_0.v @@ -0,0 +1,255 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin // on each positive edge at 25Mhz clock + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + + if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end + if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + u_arr <= 1; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 1; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 1; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 1; //0x74 right key + end + end +end + + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + sq_pos_y <= sq_pos_y - 1; + end; + + if(d_arr) begin + sq_pos_y <= sq_pos_y + 1; + end; + + if(l_arr) begin + sq_pos_x <= sq_pos_x - 1; + end; + + if(r_arr) begin + sq_pos_x <= sq_pos_x + 1; + end; + + end + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_1.v b/src/evb-yosys-demo/ice40-io-video/example_1.v new file mode 100644 index 0000000..41fab0a --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_1.v @@ -0,0 +1,263 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin // on each positive edge at 25Mhz clock + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + + if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end + if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + u_arr <= 1; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 1; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 1; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 1; //0x74 right key + end + end +end + + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + end; + + end + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_2.v b/src/evb-yosys-demo/ice40-io-video/example_2.v new file mode 100644 index 0000000..f9f7f36 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_2.v @@ -0,0 +1,263 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin // on each positive edge at 25Mhz clock + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + +/* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end +*/ if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + u_arr <= 1; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 1; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 1; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 1; //0x74 right key + end + end +end + + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + end; + + end + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_3.v b/src/evb-yosys-demo/ice40-io-video/example_3.v new file mode 100644 index 0000000..2d24702 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_3.v @@ -0,0 +1,277 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + else begin + u_arr <= 0; + d_arr <= 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + else begin + d_arr <= 0; + u_arr <= 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + else begin + l_arr <= 0; + r_arr <= 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + else begin + r_arr <= 0; + l_arr <= 1; + end + end; + + end + + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + +/* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end +*/ if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + u_arr <= 1; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 1; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 1; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 1; //0x74 right key + end + end + + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_4.v b/src/evb-yosys-demo/ice40-io-video/example_4.v new file mode 100644 index 0000000..1b38918 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_4.v @@ -0,0 +1,313 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +reg [19:0] sq_figure [0:19]; +wire [4:0] sq_fig_x; +wire [4:0] sq_fig_y; + +assign sq_fig_x = c_col - l_sq_pos_x; // our figure's x axis when in square boundary +assign sq_fig_y = c_row - u_sq_pos_y; // our figure's y axis when in square boundary + + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + sq_figure[0][19:0] <= 20'b00000000000000000000; + sq_figure[1][19:0] <= 20'b00000001111100000000; + sq_figure[2][19:0] <= 20'b00000111111111000000; + sq_figure[3][19:0] <= 20'b00011111111111110000; + sq_figure[4][19:0] <= 20'b00111111111111111000; + sq_figure[5][19:0] <= 20'b00111111111111111000; + sq_figure[6][19:0] <= 20'b01111111111111111100; + sq_figure[7][19:0] <= 20'b01111111111111111100; + sq_figure[8][19:0] <= 20'b11111111111111111110; + sq_figure[9][19:0] <= 20'b11111111111111111110; + sq_figure[10][19:0] <= 20'b11111111111111111110; + sq_figure[11][19:0] <= 20'b11111111111111111110; + sq_figure[12][19:0] <= 20'b11111111111111111110; + sq_figure[13][19:0] <= 20'b01111111111111111100; + sq_figure[14][19:0] <= 20'b01111111111111111100; + sq_figure[15][19:0] <= 20'b00111111111111111000; + sq_figure[16][19:0] <= 20'b00111111111111111000; + sq_figure[17][19:0] <= 20'b00011111111111110000; + sq_figure[18][19:0] <= 20'b00000111111111000000; + sq_figure[19][19:0] <= 20'b00000001111100000000; + + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //draw picture from video RAM + if(sq_figure[sq_fig_y][sq_fig_x] == 1) begin + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + else begin + u_arr <= 0; + d_arr <= 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + else begin + d_arr <= 0; + u_arr <= 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + else begin + l_arr <= 0; + r_arr <= 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + else begin + r_arr <= 0; + l_arr <= 1; + end + end; + + end + + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + +/* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end +*/ if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + u_arr <= 1; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 1; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 1; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 1; //0x74 right key + end + end + + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_5.v b/src/evb-yosys-demo/ice40-io-video/example_5.v new file mode 100644 index 0000000..1cb08fa --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_5.v @@ -0,0 +1,317 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +reg [19:0] sq_figure [0:19]; +wire [4:0] sq_fig_x; +wire [4:0] sq_fig_y; + +assign sq_fig_x = c_col - l_sq_pos_x; // our figure's x axis when in square boundary +assign sq_fig_y = c_row - u_sq_pos_y; // our figure's y axis when in square boundary + + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + sq_figure[0][19:0] <= 20'b00000000000000000000; + sq_figure[1][19:0] <= 20'b00000001111100000000; + sq_figure[2][19:0] <= 20'b00000111111111000000; + sq_figure[3][19:0] <= 20'b00011111111111110000; + sq_figure[4][19:0] <= 20'b00111111111111111000; + sq_figure[5][19:0] <= 20'b00111111111111111000; + sq_figure[6][19:0] <= 20'b01111111111111111100; + sq_figure[7][19:0] <= 20'b01111111111111111100; + sq_figure[8][19:0] <= 20'b11111111111111111110; + sq_figure[9][19:0] <= 20'b11111111111111111110; + sq_figure[10][19:0] <= 20'b11111111111111111110; + sq_figure[11][19:0] <= 20'b11111111111111111110; + sq_figure[12][19:0] <= 20'b11111111111111111110; + sq_figure[13][19:0] <= 20'b01111111111111111100; + sq_figure[14][19:0] <= 20'b01111111111111111100; + sq_figure[15][19:0] <= 20'b00111111111111111000; + sq_figure[16][19:0] <= 20'b00111111111111111000; + sq_figure[17][19:0] <= 20'b00011111111111110000; + sq_figure[18][19:0] <= 20'b00000111111111000000; + sq_figure[19][19:0] <= 20'b00000001111100000000; + + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //draw picture from video RAM + if(sq_figure[sq_fig_y][sq_fig_x] == 1) begin + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + else begin + u_arr <= 0; + d_arr <= 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + else begin + d_arr <= 0; + u_arr <= 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + else begin + l_arr <= 0; + r_arr <= 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + else begin + r_arr <= 0; + l_arr <= 1; + end + end; + + end + + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + +/* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end +*/ if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + u_arr <= 1; //0x75 up key + d_arr <= 0; + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 1; //0x6B left key + r_arr <= 0; + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 1; //0x72 down key + u_arr <= 0; + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 1; //0x74 right key + l_arr <= 0; + end + end + + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_6.v b/src/evb-yosys-demo/ice40-io-video/example_6.v new file mode 100644 index 0000000..5d82994 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_6.v @@ -0,0 +1,364 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +reg [19:0] arr_timer; // delay between key service + +reg [19:0] sq_figure [0:19]; + +wire [4:0] sq_fig_x; +wire [4:0] sq_fig_y; + +assign sq_fig_x = c_col - l_sq_pos_x; // our figure's x axis when in square boundary +assign sq_fig_y = c_row - u_sq_pos_y; // our figure's y axis when in square boundary + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + + + sq_figure[0][19:0] <= 20'b00000000000000000000; + sq_figure[1][19:0] <= 20'b00000001111100000000; + sq_figure[2][19:0] <= 20'b00000111111111000000; + sq_figure[3][19:0] <= 20'b00011111111111110000; + sq_figure[4][19:0] <= 20'b00111111111111111000; + sq_figure[5][19:0] <= 20'b00111111111111111000; + sq_figure[6][19:0] <= 20'b01111111111111111100; + sq_figure[7][19:0] <= 20'b01111111111111111100; + sq_figure[8][19:0] <= 20'b11111111111111111110; + sq_figure[9][19:0] <= 20'b11111111111111111110; + sq_figure[10][19:0] <= 20'b11111111111111111110; + sq_figure[11][19:0] <= 20'b11111111111111111110; + sq_figure[12][19:0] <= 20'b11111111111111111110; + sq_figure[13][19:0] <= 20'b01111111111111111100; + sq_figure[14][19:0] <= 20'b01111111111111111100; + sq_figure[15][19:0] <= 20'b00111111111111111000; + sq_figure[16][19:0] <= 20'b00111111111111111000; + sq_figure[17][19:0] <= 20'b00011111111111110000; + sq_figure[18][19:0] <= 20'b00000111111111000000; + sq_figure[19][19:0] <= 20'b00000001111100000000; + + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square + //vga_r_r <= 7; + //vga_g_r <= 0; + //vga_b_r <= 7; + if(sq_figure[sq_fig_y][sq_fig_x] == 1) begin + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + else begin + u_arr <= 0; + d_arr <= 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + else begin + d_arr <= 0; + u_arr <= 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + else begin + l_arr <= 0; + r_arr <= 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + else begin + r_arr <= 0; + l_arr <= 1; + end + end; + + end + + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + +/* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end +*/ + arr_timer <= arr_timer + 1; + + if(arr_timer == 0) begin + if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + if(u_arr == 1) begin + u_arr <= 1; //0x75 up key + d_arr <= 0; + l_arr <= 0; + r_arr <= 0; + end + else begin + u_arr <= 1; //0x75 up key + d_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h6b) begin + if(l_arr == 1) begin + l_arr <= 1; //0x6B left key + r_arr <= 0; + u_arr <= 0; + d_arr <= 0; + end + else begin + l_arr <= 1; //0x6B left key + r_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h72) begin + if(d_arr == 1) begin + d_arr <= 1; //0x72 down key + u_arr <= 0; + l_arr <= 0; + r_arr <= 0; + end + else begin + d_arr <= 1; //0x72 down key + u_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h74) begin + if(r_arr == 1) begin + r_arr <= 1; //0x74 right key + l_arr <= 0; + u_arr <= 0; + d_arr <= 0; + end + else begin + r_arr <= 1; //0x74 right key + l_arr <= 0; + end + ps2_data_reg <= 0; + end + end + end + + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/example_7.v b/src/evb-yosys-demo/ice40-io-video/example_7.v new file mode 100644 index 0000000..dbd0b1c --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/example_7.v @@ -0,0 +1,371 @@ +`default_nettype none //disable implicit definitions by Verilog + +module top( //top module and signals wired to FPGA pins + CLK100MHz, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + ps2_clk, + ps2_data +); + +input CLK100MHz; // Oscillator input 100Mhz +output [2:0] vga_r; // VGA Red 3 bit +output [2:0] vga_g; // VGA Green 3 bit +output [2:0] vga_b; // VGA Blue 3 bit +output vga_hs; // H-sync pulse +output vga_vs; // V-sync pulse +input ps2_clk; // PS2 clock +input ps2_data; // PS2 data + + +parameter h_pulse = 96; //H-SYNC pulse width 96 * 40 ns (25 Mhz) = 3.84 uS +parameter h_bp = 48; //H-BP back porch pulse width +parameter h_pixels = 640; //H-PIX Number of pixels horisontally +parameter h_fp = 16; //H-FP front porch pulse width +parameter h_pol = 1'b0; //H-SYNC polarity +parameter h_frame = 800; //800 = 96 (H-SYNC) + 48 (H-BP) + 640 (H-PIX) + 16 (H-FP) +parameter v_pulse = 2; //V-SYNC pulse width +parameter v_bp = 33; //V-BP back porch pulse width +parameter v_pixels = 480; //V-PIX Number of pixels vertically +parameter v_fp = 10; //V-FP front porch pulse width +parameter v_pol = 1'b1; //V-SYNC polarity +parameter v_frame = 525; // 525 = 2 (V-SYNC) + 33 (V-BP) + 480 (V-PIX) + 10 (V-FP) + +parameter square_size = 10; //size of the square we will move +parameter init_x = 320; //initial square position X +parameter init_y = 240; //initial square position Y + +reg [1:0] clk_div; // 2 bit counter +wire vga_clk; + +assign vga_clk = clk_div[1]; // 25Mhz clock = 100Mhz divided by 2-bit counter + +always @ (posedge CLK100MHz) begin // 2-bt counter ++ on each positive edge of 100Mhz clock + clk_div <= clk_div + 2'b1; +end + +reg [2:0] vga_r_r; //VGA color registers R,G,B x 3 bit +reg [2:0] vga_g_r; +reg [2:0] vga_b_r; +reg vga_hs_r; //H-SYNC register +reg vga_vs_r; //V-SYNC register + +assign vga_r = vga_r_r; //assign the output signals for VGA to the VGA registers +assign vga_g = vga_g_r; +assign vga_b = vga_b_r; +assign vga_hs = vga_hs_r; +assign vga_vs = vga_vs_r; + +reg [7:0] timer_t = 8'b0; // 8 bit timer with 0 initialization +reg reset = 1; +reg [9:0] c_row; //complete frame register row +reg [9:0] c_col; //complete frame register colum +reg [9:0] c_hor; //visible frame register horisontally +reg [9:0] c_ver; //visible frame register vertically + +reg disp_en; //display enable flag + +reg [9:0] sq_pos_x; //position of square center X, Y +reg [9:0] sq_pos_y; + +wire [9:0] l_sq_pos_x; //upper left and down right corners of the square +wire [9:0] r_sq_pos_x; +wire [9:0] u_sq_pos_y; +wire [9:0] d_sq_pos_y; + +assign l_sq_pos_x = sq_pos_x - square_size; +assign r_sq_pos_x = sq_pos_x + square_size; +assign u_sq_pos_y = sq_pos_y - square_size; +assign d_sq_pos_y = sq_pos_y + square_size; + +reg [3:0] ps2_cntr; // 4-bit PS2 clock counter +reg [7:0] ps2_data_reg; // 8-bit PS2 data register +reg [7:0] ps2_data_reg_prev; // previous 8-bit PS data register +reg [7:0] ps2_data_reg_prev1; // previous previous 8-bit data register +reg [10:0] ps2_dat_r; // 11-bit complete PS2 frame register + +reg [1:0] ps2_clk_buf; // PS2 clock buffer +wire ps2_clk_pos; // PS2 positive edge detected signal + +reg u_arr = 0; //PS2 arrow keys detect flags +reg l_arr = 0; +reg d_arr = 0; +reg r_arr = 0; + +reg [20:0] arr_timer; // delay between key service + +reg [19:0] sq_figure [0:19]; + +wire [4:0] sq_fig_x; +wire [4:0] sq_fig_y; + +assign sq_fig_x = c_col - l_sq_pos_x; // our figure's x axis when in square boundary +assign sq_fig_y = c_row - u_sq_pos_y; // our figure's y axis when in square boundary + +assign ps2_clk_pos = (ps2_clk_buf == 2'b01); // edge detector positive edge is when the buffer is '10' + +always @ (posedge vga_clk) begin //25Mhz clock + + if(timer_t > 250) begin // generate 10 uS RESET signal + reset <= 0; + end + else begin + reset <= 1; //while in reset display is disabled, suare is set to initial position + timer_t <= timer_t + 1; + disp_en <= 0; + sq_pos_x <= init_x; + sq_pos_y <= init_y; + end + + if(reset == 1) begin //while RESET is high init counters + + + sq_figure[0][19:0] <= 20'b00000000000000000000; + sq_figure[1][19:0] <= 20'b00000001111100000000; + sq_figure[2][19:0] <= 20'b00000111111111000000; + sq_figure[3][19:0] <= 20'b00011111111111110000; + sq_figure[4][19:0] <= 20'b00111111111111111000; + sq_figure[5][19:0] <= 20'b00111111111111111000; + sq_figure[6][19:0] <= 20'b01111111111111111100; + sq_figure[7][19:0] <= 20'b01111111111111111100; + sq_figure[8][19:0] <= 20'b11111111111111111110; + sq_figure[9][19:0] <= 20'b11111111111111111110; + sq_figure[10][19:0] <= 20'b11111111111111111110; + sq_figure[11][19:0] <= 20'b11111111111111111110; + sq_figure[12][19:0] <= 20'b11111111111111111110; + sq_figure[13][19:0] <= 20'b01111111111111111100; + sq_figure[14][19:0] <= 20'b01111111111111111100; + sq_figure[15][19:0] <= 20'b00111111111111111000; + sq_figure[16][19:0] <= 20'b00111111111111111000; + sq_figure[17][19:0] <= 20'b00011111111111110000; + sq_figure[18][19:0] <= 20'b00000111111111000000; + sq_figure[19][19:0] <= 20'b00000001111100000000; + + c_hor <= 0; + c_ver <= 0; + vga_hs_r <= 1; + vga_vs_r <= 0; + c_row <= 0; + c_col <= 0; + end + else begin // update current beam position + if(c_hor < h_frame - 1) begin + c_hor <= c_hor + 1; + end + else begin + c_hor <= 0; + if(c_ver < v_frame - 1) begin + c_ver <= c_ver + 1; + end + else begin + c_ver <= 0; + end + end + end + if(c_hor < h_pixels + h_fp + 1 || c_hor > h_pixels + h_fp + h_pulse) begin // H-SYNC generator + vga_hs_r <= ~h_pol; + end + else begin + vga_hs_r <= h_pol; + end + if(c_ver < v_pixels + v_fp || c_ver > v_pixels + v_fp + v_pulse) begin //V-SYNC generator + vga_vs_r <= ~v_pol; + end + else begin + vga_vs_r <= v_pol; + end + if(c_hor < h_pixels) begin //c_col and c_row counters are updated only in the visible time-frame + c_col <= c_hor; + end + if(c_ver < v_pixels) begin + c_row <= c_ver; + end + if(c_hor < h_pixels && c_ver < v_pixels) begin //VGA color signals are enabled only in the visible time frame + disp_en <= 1; + end + else begin + disp_en <= 0; + end + if(disp_en == 1 && reset == 0) begin + if(c_row == 0 || c_col == 0 || c_row == v_pixels-1 || c_col == h_pixels-1) begin //generate red frame with size 640x480 + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 0; + end + else if(c_col > l_sq_pos_x && c_col < r_sq_pos_x && c_row > u_sq_pos_y && c_row < d_sq_pos_y) begin //generate blue square + //vga_r_r <= 7; + //vga_g_r <= 0; + //vga_b_r <= 7; + if(sq_figure[sq_fig_y][sq_fig_x] == 1) begin + vga_r_r <= 7; + vga_g_r <= 0; + vga_b_r <= 7; + end + else begin + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //everything else is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + end + else begin //when display is not enabled everything is black + vga_r_r <= 0; + vga_g_r <= 0; + vga_b_r <= 0; + end + + if(c_row == 1 && c_col == 1) begin //once per video frame + if(u_arr) begin + if (sq_pos_y > square_size) begin + sq_pos_y <= sq_pos_y - 1; + end + else begin + u_arr <= 0; + d_arr <= 1; + end + end; + + if(d_arr) begin + if (sq_pos_y < (v_pixels - 1 - square_size)) begin + sq_pos_y <= sq_pos_y + 1; + end + else begin + d_arr <= 0; + u_arr <= 1; + end + end; + + if(l_arr) begin + if (sq_pos_x > square_size) begin + sq_pos_x <= sq_pos_x - 1; + end + else begin + l_arr <= 0; + r_arr <= 1; + end + end; + + if(r_arr) begin + if (sq_pos_x < (h_pixels - 1 - square_size)) begin + sq_pos_x <= sq_pos_x + 1; + end + else begin + r_arr <= 0; + l_arr <= 1; + end + end; + + end + + ps2_clk_buf[1:0] <= {ps2_clk_buf[0], ps2_clk}; // shift old value left and get current value of ps2_clk + if(ps2_clk_pos == 1) begin // on positive edge + ps2_cntr <= ps2_cntr + 1; + if(ps2_cntr == 10) begin // when we got 10 clocks save the PS2 data to ps2_data_reg, ps2_data_reg_prev and ps2_data_reg_prev1 + ps2_cntr <= 0; // so we have last 3 data values captured from PS2 keyboard + ps2_data_reg[7] <= ps2_dat_r[0]; + ps2_data_reg[6] <= ps2_dat_r[1]; + ps2_data_reg[5] <= ps2_dat_r[2]; + ps2_data_reg[4] <= ps2_dat_r[3]; + ps2_data_reg[3] <= ps2_dat_r[4]; + ps2_data_reg[2] <= ps2_dat_r[5]; + ps2_data_reg[1] <= ps2_dat_r[6]; + ps2_data_reg[0] <= ps2_dat_r[7]; + ps2_data_reg_prev <= ps2_data_reg; + ps2_data_reg_prev1 <= ps2_data_reg_prev; + end + ps2_dat_r <= {ps2_dat_r[9:0], ps2_data}; // data shift left + end + +/* if(ps2_data_reg_prev1 == 8'he0 && ps2_data_reg_prev == 8'hf0) begin // 0xE0 0xF0 sequaence means key released + if(ps2_data_reg == 8'h75) begin + u_arr <= 0; //0x75 up key + end + else if(ps2_data_reg == 8'h6b) begin + l_arr <= 0; //0x6B left key + end + else if(ps2_data_reg == 8'h72) begin + d_arr <= 0; //0x72 down key + end + else if(ps2_data_reg == 8'h74) begin + r_arr <= 0; //0x74 right key + end + end +*/ + arr_timer <= arr_timer + 1; + + if(arr_timer == 0) begin + + sq_figure[8][19:0] <= sq_figure[8][19:0] ^ 20'b00000001111000000000; + sq_figure[9][19:0] <= sq_figure[9][19:0] ^ 20'b00000001111000000000; + sq_figure[10][19:0] <= sq_figure[10][19:0] ^ 20'b00000001111000000000; + sq_figure[11][19:0] <= sq_figure[11][19:0] ^ 20'b00000001111000000000; + + + if(ps2_data_reg_prev == 8'he0) begin //0xE0 means key pressed + if(ps2_data_reg == 8'h75) begin + if(u_arr == 1) begin + u_arr <= 1; //0x75 up key + d_arr <= 0; + l_arr <= 0; + r_arr <= 0; + end + else begin + u_arr <= 1; //0x75 up key + d_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h6b) begin + if(l_arr == 1) begin + l_arr <= 1; //0x6B left key + r_arr <= 0; + u_arr <= 0; + d_arr <= 0; + end + else begin + l_arr <= 1; //0x6B left key + r_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h72) begin + if(d_arr == 1) begin + d_arr <= 1; //0x72 down key + u_arr <= 0; + l_arr <= 0; + r_arr <= 0; + end + else begin + d_arr <= 1; //0x72 down key + u_arr <= 0; + end + ps2_data_reg <= 0; + end + if(ps2_data_reg == 8'h74) begin + if(r_arr == 1) begin + r_arr <= 1; //0x74 right key + l_arr <= 0; + u_arr <= 0; + d_arr <= 0; + end + else begin + r_arr <= 1; //0x74 right key + l_arr <= 0; + end + ps2_data_reg <= 0; + end + end + end + + +end + +endmodule diff --git a/src/evb-yosys-demo/ice40-io-video/ice40-io-video.pcf b/src/evb-yosys-demo/ice40-io-video/ice40-io-video.pcf new file mode 100644 index 0000000..1684a64 --- /dev/null +++ b/src/evb-yosys-demo/ice40-io-video/ice40-io-video.pcf @@ -0,0 +1,14 @@ +set_io CLK100MHz J3 +set_io vga_r[0] E3 +set_io vga_r[1] H5 +set_io vga_r[2] F3 +set_io vga_g[0] H3 +set_io vga_g[1] F2 +set_io vga_g[2] H6 +set_io vga_b[0] F1 +set_io vga_b[1] H4 +set_io vga_b[2] G2 +set_io vga_hs J4 +set_io vga_vs H2 +set_io ps2_clk G1 +set_io ps2_data J5 diff --git a/src/evb-yosys-demo/ice40hx8k-evb/.gitignore b/src/evb-yosys-demo/ice40hx8k-evb/.gitignore new file mode 100644 index 0000000..c1fa30b --- /dev/null +++ b/src/evb-yosys-demo/ice40hx8k-evb/.gitignore @@ -0,0 +1,4 @@ +example.bin +example.blif +example.asc +example.rpt diff --git a/src/evb-yosys-demo/ice40hx8k-evb/Makefile b/src/evb-yosys-demo/ice40hx8k-evb/Makefile new file mode 100644 index 0000000..1bb5bb0 --- /dev/null +++ b/src/evb-yosys-demo/ice40hx8k-evb/Makefile @@ -0,0 +1,49 @@ +PREFIX=../../.. +BINDIR=${PREFIX}/bin + +#PREBUILT=/root/projects/tim_ac3rf/prebuild/oss-cad-suite/ +#BINDIR=${PREBUILT}/libexec +#LD_LIBRARY_PATH:="${PREBUILT}/lib:${LD_LIBRARY_PATH}" + +YOSYS=${BINDIR}/yosys +NEXTPNR=${BINDIR}/nextpnr-ice40 +ICEPACK=${BINDIR}/icepack +ICETIME=${BINDIR}/icetime +FLASH=${BINDIR}/flash + +BUILDDIR = ./build +FPGA_TYPE = hx8k +FPGA_PKG = ct256 +PCF = ice40hx8k-evb.pcf +RMDIR = rmdir + +# Targets +example: $(BUILDDIR)/example.rpt $(BUILDDIR)/example.bin + +flash: $(BUILDDIR)/example.bin + ${FLASH} $(BUILDDIR)/example.bin + +$(BUILDDIR)/%.json: %.v + @mkdir -p $(@D) + #LD_LIBRARY_PATH=${LD_LIBRARY_PATH} + ${YOSYS} -ql $(subst .json,,$@).log -p 'synth_ice40 -abc9 -device u -top top -json $@' $< + +%.asc: %.json + ${NEXTPNR} --${FPGA_TYPE} --package ${FPGA_PKG} --json $< --pcf ${PCF} --asc $@ + +%.bin: %.asc + ${ICEPACK} $< $@ + +%.rpt: %.asc + ${ICETIME} -d $(FPGA_TYPE) -mtr $@ $< + +all: example + +clean: + rm -f $(BUILDDIR)/*.asc $(BUILDDIR)/*.bin $(BUILDDIR)/*.rpt $(BUILDDIR)/*.log $(BUILDDIR)/*.json + $(RMDIR) $(BUILDDIR) + +# Uncomment this line if you want to keep the intermediate .json and .asc files +# .PRECIOUS: $(BUILDDIR)/%.json %.asc + +.PHONY: all prog clean example diff --git a/src/evb-yosys-demo/ice40hx8k-evb/README b/src/evb-yosys-demo/ice40hx8k-evb/README new file mode 100644 index 0000000..8e2c1e0 --- /dev/null +++ b/src/evb-yosys-demo/ice40hx8k-evb/README @@ -0,0 +1,6 @@ +This example is for iCE40HX1K-EVB board + +www.olimex.com/wiki/iCE40HX1K-EVB + +you need OLIMEXINO-32U4 set as programmer to program the board + diff --git a/src/evb-yosys-demo/ice40hx8k-evb/example.v b/src/evb-yosys-demo/ice40hx8k-evb/example.v new file mode 100644 index 0000000..0aa36d9 --- /dev/null +++ b/src/evb-yosys-demo/ice40hx8k-evb/example.v @@ -0,0 +1,66 @@ +module top( //top module + CLK, + BUT1, + BUT2, + LED1, + LED2 +); + +input CLK; //input 100Mhz clock +input BUT1; //input signal from button 1 +input BUT2; //input signal from button 2 +output LED1; //output signal to LED1 +output LED2; //output signal to LED2 + +reg BUT1_r; //register to keep button 1 state +reg BUT2_r; //register to keep button 2 state +reg LED1_m0_r; //LED1 value in mode = 0 +reg LED2_m0_r; //LED2 value in mode = 0 +reg LED1_m1_r; //LED1 value in mode = 1 +reg LED2_m1_r; //LED2 value in mode = 1 +reg [14:0] cntr; // 15 bit counter for LED blink timing +reg [14:0] rst_cnt=0; // 15 bit counter for button debounce +reg mode=1; //mode set to 1 initially +reg [11:0] clk_div; // 12 bit counter + +wire clk_24KHz; //signal with approx 24KHz clock +wire reset; //used for button debounce + +assign reset = rst_cnt[14]; //reset signal is connected to bit15 of rst_cnt +assign LED1 = mode ? LED1_m1_r : LED1_m0_r; //multiplexer controlled by mode which connects LED1_m1_r or LED1_m0_r to LED1 +assign LED2 = mode ? LED2_m1_r : LED2_m0_r; //multiplexer controlled by mode which connects LED2_m1_r or LED2_m0_r to LED2 +assign clk_24KHz = clk_div[11]; //100 000 000 Hz / 4096 = 24414 Hz + +always @ (posedge CLK) begin //on each positive edge of 100Mhz clock increment clk_div + clk_div <= clk_div + 12'b1; +end + +always @ (posedge clk_24KHz) begin //on each positive edge of 24414Hz clock + BUT1_r <= BUT1; //capture button 1 state to BUT1_r + BUT2_r <= BUT2; //capture button 2 state to BUT2_r + cntr <= cntr + 15'd1; //increment cntr LED blink counter + + if(reset == 1'b0) begin //if bit15 of rst_cnt is not set yet + rst_cnt <= rst_cnt + 15'd1; //increment the counter rst_cnt + end + + if(BUT1_r == 1'b0 && BUT2_r == 1'b0 && reset == 1'b1) begin //if bit15 of rst_cnt is set and both buttons are pressed + mode <= mode ^ 1'b1; //toggle the mode + rst_cnt <= 15'd0; //clear debounce rst_cnt + end + + LED1_m0_r <= ~BUT1_r; //copy inversed state of button 1 to LED1_m0_r + LED2_m0_r <= ~BUT2_r; //copy inversed state of button 2 to LED2_m0_r + + if(cntr == 15'd12207) begin //when 0.5s pass + LED1_m1_r <= 1'b0; //reset LED1_m1_r + LED2_m1_r <= 1'b1; //set LED2_m1_r + end + if(cntr > 15'd24414) begin //when 1.0s pass + cntr <= 15'd0; //clear cntr + LED1_m1_r <= 1'b1; //set LED1_m1_r + LED2_m1_r <= 1'b0; //reset LED2_m1_r + end +end + +endmodule diff --git a/src/evb-yosys-demo/ice40hx8k-evb/ice40hx8k-evb.pcf b/src/evb-yosys-demo/ice40hx8k-evb/ice40hx8k-evb.pcf new file mode 100644 index 0000000..3d072ff --- /dev/null +++ b/src/evb-yosys-demo/ice40hx8k-evb/ice40hx8k-evb.pcf @@ -0,0 +1,5 @@ +set_io CLK J3 +set_io BUT1 K11 +set_io BUT2 P13 +set_io LED1 M12 +set_io LED2 R16 diff --git a/src/flashrom b/src/flashrom new file mode 160000 index 0000000..1776bb4 --- /dev/null +++ b/src/flashrom @@ -0,0 +1 @@ +Subproject commit 1776bb46ba6ea3d1ab2ec3f0cd88158aabed7400 diff --git a/src/icestorm b/src/icestorm new file mode 160000 index 0000000..d20a5e9 --- /dev/null +++ b/src/icestorm @@ -0,0 +1 @@ +Subproject commit d20a5e9001f46262bf0cef220f1a6943946e421d diff --git a/src/nextpnr b/src/nextpnr new file mode 160000 index 0000000..051bdb1 --- /dev/null +++ b/src/nextpnr @@ -0,0 +1 @@ +Subproject commit 051bdb12b3b695d74a829a231f3e3bf4d0a26323 diff --git a/src/yosys b/src/yosys new file mode 160000 index 0000000..cee3cb3 --- /dev/null +++ b/src/yosys @@ -0,0 +1 @@ +Subproject commit cee3cb31b98e3b67af3165969c8cfc0616c37e19 -- cgit v1.2.3