//////////////////////////////////////////////////////////////////////////// // _____ // / _______ Copyright (C) 2013-2022 Efinix Inc. All rights reserved. // / / \ // / / .. / design_modules.v // / / .' / // __/ /.' / Description: // __ \ / Modules for SapphireSoC example design // /_/ /\ \_____/ / // ____/ \_______/ // // *********************************************************************** // Revisions: // 1.0 Initial rev // 1.1 Added Custom ALU // 1.2 Fixed AXI4 slave read first issue // 1.3 Added axi full-duplex to half-duplex converter // *********************************************************************** `timescale 1ns/1ps module apb3_slave #( // user parameter starts here // parameter ADDR_WIDTH = 16, parameter DATA_WIDTH = 32, parameter NUM_REG = 4 ) ( // user logic starts here input clk, input resetn, input [ADDR_WIDTH-1:0] PADDR, input PSEL, input PENABLE, output PREADY, input PWRITE, input [DATA_WIDTH-1:0] PWDATA, output [DATA_WIDTH-1:0] PRDATA, output PSLVERROR ); /////////////////////////////////////////////////////////////////////////////// localparam [1:0] IDLE = 2'b00, SETUP = 2'b01, ACCESS = 2'b10; integer byteIndex; reg [DATA_WIDTH-1:0] slaveReg [0:NUM_REG-1]; reg [DATA_WIDTH-1:0] slaveRegOut; reg [1:0] busState, busNext; reg slaveReady; wire actWrite, actRead; reg [31:0] lfsr; wire lfsr_stop; /////////////////////////////////////////////////////////////////////////////// always@(posedge clk or negedge resetn) begin if(!resetn) busState <= IDLE; else busState <= busNext; end always@(*) begin busNext = busState; case(busState) IDLE: begin if(PSEL && !PENABLE) busNext = SETUP; else busNext = IDLE; end SETUP: begin if(PSEL && PENABLE) busNext = ACCESS; else busNext = IDLE; end ACCESS: begin if(PREADY) busNext = IDLE; else busNext = ACCESS; end default: begin busNext = IDLE; end endcase end assign actWrite = PWRITE & (busState == ACCESS); assign actRead = !PWRITE & (busState == ACCESS); assign PSLVERROR = 1'b0; assign PRDATA = slaveRegOut; assign PREADY = slaveReady & & (busState !== IDLE); always@ (posedge clk) begin slaveReady <= actWrite | actRead; end always@ (posedge clk or negedge resetn) begin if(!resetn) for(byteIndex = 0; byteIndex < NUM_REG; byteIndex = byteIndex + 1) slaveReg[byteIndex] <= {DATA_WIDTH{1'b0}}; else begin if(actWrite) begin for(byteIndex = 0; byteIndex < NUM_REG; byteIndex = byteIndex + 1) if (PADDR[3:0] == (byteIndex*4)) slaveReg[byteIndex] <= PWDATA; end else begin slaveReg[0] <= lfsr; for(byteIndex = 1; byteIndex < NUM_REG; byteIndex = byteIndex + 1) slaveReg[byteIndex] <= slaveReg[byteIndex]; end end end always@ (posedge clk or negedge resetn) begin if(!resetn) slaveRegOut <= {DATA_WIDTH{1'b0}}; else begin if(actRead) slaveRegOut <= slaveReg[PADDR[7:2]]; else slaveRegOut <= slaveRegOut; end end assign lfsr_stop = slaveReg[1][0]; //custom logics always@(posedge clk or negedge resetn) begin if (!resetn) lfsr <= 'd1; else begin if(!lfsr_stop) begin lfsr[31] <= lfsr[0]; lfsr[30] <= lfsr[31]; lfsr[29] <= lfsr[30]; lfsr[28] <= lfsr[29]; lfsr[27] <= lfsr[28]; lfsr[26] <= lfsr[27]; lfsr[25] <= lfsr[26]; lfsr[24] <= lfsr[25]; lfsr[23] <= lfsr[24]; lfsr[22] <= lfsr[23]; lfsr[21] <= lfsr[22]; lfsr[20] <= lfsr[21]; lfsr[19] <= lfsr[20]; lfsr[18] <= lfsr[19]; lfsr[17] <= lfsr[18]; lfsr[16] <= lfsr[17]; lfsr[15] <= lfsr[16]; lfsr[14] <= lfsr[15]; lfsr[13] <= lfsr[14]; lfsr[12] <= lfsr[13]; lfsr[11] <= lfsr[12]; lfsr[10] <= lfsr[11]; lfsr[9 ] <= lfsr[10]; lfsr[8 ] <= lfsr[9 ]; lfsr[7 ] <= lfsr[8 ]; lfsr[6 ] <= lfsr[7 ]; lfsr[5 ] <= lfsr[6 ]; lfsr[4 ] <= lfsr[5 ]; lfsr[3 ] <= lfsr[4 ] ^ lfsr[0]; lfsr[2 ] <= lfsr[3 ]; lfsr[1 ] <= lfsr[2 ]; lfsr[0 ] <= lfsr[1 ] ^ lfsr[0]; end else begin lfsr <= lfsr; end end end endmodule // *********************************************************************** module axi4_slave #( parameter ADDR_WIDTH = 32, parameter DATA_WIDTH = 32 ) ( //custom logic starts here output axi_interrupt, // input axi_aclk, input axi_resetn, //AW input [7:0] axi_awid, input [ADDR_WIDTH-1:0] axi_awaddr, input [7:0] axi_awlen, input [2:0] axi_awsize, input [1:0] axi_awburst, input axi_awlock, input [3:0] axi_awcache, input [2:0] axi_awprot, input [3:0] axi_awqos, input [3:0] axi_awregion, input axi_awvalid, output axi_awready, //W input [DATA_WIDTH-1:0] axi_wdata, input [(DATA_WIDTH/8)-1:0] axi_wstrb, input axi_wlast, input axi_wvalid, output axi_wready, //B output [7:0] axi_bid, output [1:0] axi_bresp, output axi_bvalid, input axi_bready, //AR input [7:0] axi_arid, input [ADDR_WIDTH-1:0] axi_araddr, input [7:0] axi_arlen, input [2:0] axi_arsize, input [1:0] axi_arburst, input axi_arlock, input [3:0] axi_arcache, input [2:0] axi_arprot, input [3:0] axi_arqos, input [3:0] axi_arregion, input axi_arvalid, output axi_arready, //R output [7:0] axi_rid, output [DATA_WIDTH-1:0] axi_rdata, output [1:0] axi_rresp, output axi_rlast, output axi_rvalid, input axi_rready ); /////////////////////////////////////////////////////////////////////////////// localparam RAM_SIZE = 2048; localparam RAMW = $clog2(RAM_SIZE); localparam [2:0] IDLE = 3'h0, PRE_WR = 3'h1, WR = 3'h2, WR_RESP = 3'h3, PRE_RD = 3'h4, RD = 3'h5; reg [2:0] busState, busNext; wire busReady, busPreWrite, busWrite, busWriteResp, busPreRead, busRead; wire awWrap, arWrap; reg [7:0] awidReg; reg [ADDR_WIDTH-1:0] awaddrReg; reg [7:0] awlenReg; reg [2:0] awsizeReg; reg [1:0] awburstReg, awlockReg; reg [3:0] awcacheReg; reg [2:0] awprotReg; reg [3:0] awqosReg; reg [3:0] awregionReg; reg [7:0] aridReg; reg [ADDR_WIDTH-1:0] araddrReg; reg [7:0] arlenReg; reg [2:0] arsizeReg; reg [1:0] arburstReg, arlockReg; reg [3:0] arcacheReg; reg [2:0] arprotReg; reg [3:0] arqosReg; reg [3:0] arregionReg; reg [31:0] awaddr_base; wire [31:0] awWrapSize; reg [7:0] decodeAwsize; wire [31:0] araddr_wrap; reg [7:0] decodeArsize; reg [31:0] araddr_base; wire [31:0] arWrapSize; reg [7:0] ridReg; reg [1:0] rrespReg; reg [1:0] rlastReg; wire pWr_done; wire pRd_done; wire awaddr_ext; wire araddr_ext; wire [(DATA_WIDTH/8)-1:0] rlast; wire [(DATA_WIDTH/8)-1:0] rvalid; //custom logic wire [9:0] wdata [0:3]; wire wEnable[0:3]; wire [9:0] rdata [0:3]; wire [31:0] data_o; wire rEnable; reg r_axi_interrupt; /////////////////////////////////////////////////////////////////////////////// always@ (posedge axi_aclk or negedge axi_resetn) begin if(!axi_resetn) busState <= IDLE; else busState <= busNext; end always@ (*) begin busNext = busState; case(busState) IDLE: begin if(axi_awvalid) busNext = PRE_WR; else if(axi_arvalid) busNext = PRE_RD; else busNext = IDLE; end PRE_WR: begin if(pWr_done) busNext = WR; else busNext = PRE_WR; end WR: begin if(axi_wlast) busNext = WR_RESP; else busNext = WR; end WR_RESP: begin if(axi_bready) busNext = IDLE; else busNext = WR_RESP; end PRE_RD: begin if(pRd_done) busNext = RD; else busNext = PRE_RD; end RD: begin if(axi_rlast && axi_rready) busNext = IDLE; else busNext = RD; end default: busNext = IDLE; endcase end assign busReady = (busState == IDLE); assign busPreWrite = (busState == PRE_WR); assign busWrite = (busState == WR); assign busWriteResp = (busState == WR_RESP); assign busPreRead = (busState == PRE_RD); assign busRead = (busState == RD); //PRE_WRITE assign pWr_done = (awburstReg == 2'b10)? awaddr_ext : 1'b1; //AW Control assign axi_awready = busReady; //Wrap Control always@ (posedge axi_aclk or negedge axi_resetn) begin if (!axi_resetn) awaddr_base <= 'h0; else begin if(busReady) awaddr_base <= 'h0; else if(busPreWrite && !awaddr_ext) awaddr_base <= awaddr_base + awWrapSize; else awaddr_base <= awaddr_base; end end assign awaddr_ext = busPreWrite ? (awaddr_base[RAMW:0] > awaddrReg[RAMW:0]) : 1'b0; assign awWrap = busWrite && (axi_awburst == 2'b10) ? (awaddrReg[RAMW:0] == awaddr_base - 4) : 1'b0; assign awWrapSize = (DATA_WIDTH/8) * awlenReg; //AW Info always@ (posedge axi_aclk) begin if(axi_awvalid) begin awidReg <= axi_awid; awlenReg <= axi_awlen + 1'b1; awsizeReg <= axi_awsize; awburstReg <= axi_awburst; awlockReg <= axi_awlock; awcacheReg <= axi_awcache; awprotReg <= axi_awprot; awqosReg <= axi_awqos; awregionReg <= axi_awregion; end else begin awidReg <= awidReg; awlenReg <= awlenReg; awsizeReg <= awsizeReg; awburstReg <= awburstReg; awlockReg <= awlockReg; awcacheReg <= awcacheReg; awprotReg <= awprotReg; awqosReg <= awqosReg; awregionReg <= awregionReg; end end always@ (awsizeReg) begin case(awsizeReg) 3'h0:decodeAwsize <= 8'd1; 3'h1:decodeAwsize <= 8'd2; 3'h2:decodeAwsize <= 8'd4; 3'h3:decodeAwsize <= 8'd8; 3'h4:decodeAwsize <= 8'd16; 3'h5:decodeAwsize <= 8'd32; 3'h6:decodeAwsize <= 8'd64; 3'h7:decodeAwsize <= 8'd128; default:decodeAwsize <= 8'd1; endcase end always@ (posedge axi_aclk) begin if(axi_awvalid) awaddrReg <= axi_awaddr; else if (busWrite) begin case(awburstReg) 2'b00://fixed burst awaddrReg <= awaddrReg; 2'b01://incremental burst awaddrReg <= awaddrReg + decodeAwsize; 2'b10://wrap burst begin if(awWrap) awaddrReg <= awaddrReg - awWrapSize; else awaddrReg <= awaddrReg + decodeAwsize; end default: awaddrReg <= awaddrReg; endcase end end //W operation assign axi_wready = busWrite; //B Response assign axi_bid = awidReg; assign axi_bresp = 2'b00; assign axi_bvalid = busWriteResp; //PRE_READ assign pRd_done = (arburstReg == 2'b10)? araddr_ext : 1'b1; //AR Control assign axi_arready = busReady; //Wrap Control always@ (posedge axi_aclk or negedge axi_resetn) begin if (!axi_resetn) araddr_base <= 'h0; else begin if(busReady) araddr_base <= 'h0; else if(busPreRead && !araddr_ext) araddr_base <= araddr_base + arWrapSize; else araddr_base <= araddr_base; end end assign araddr_ext = busPreRead ? (araddr_base[RAMW:0] > araddrReg[RAMW:0]) : 1'b0; assign arWrap = (busRead && axi_arburst == 2'b10) ? (araddrReg[RAMW:0] == araddr_base - 4) : 1'b0; assign arWrapSize = (DATA_WIDTH/8) * arlenReg; //AR Info always@ (posedge axi_aclk) begin if(axi_arvalid) begin aridReg <= axi_arid; arlenReg <= axi_arlen + 1'b1; arsizeReg <= axi_arsize; arburstReg <= axi_arburst; arlockReg <= axi_arlock; arcacheReg <= axi_arcache; arprotReg <= axi_arprot; arqosReg <= axi_arqos; arregionReg <= axi_arregion; end else begin aridReg <= aridReg; arlenReg <= arlenReg; arsizeReg <= arsizeReg; arburstReg <= arburstReg; arlockReg <= arlockReg; arcacheReg <= arcacheReg; arprotReg <= arprotReg; arqosReg <= arqosReg; arregionReg <= arregionReg; end end always@ (arsizeReg) begin case(arsizeReg) 3'h0:decodeArsize <= 8'd1; 3'h1:decodeArsize <= 8'd2; 3'h2:decodeArsize <= 8'd4; 3'h3:decodeArsize <= 8'd8; 3'h4:decodeArsize <= 8'd16; 3'h5:decodeArsize <= 8'd32; 3'h6:decodeArsize <= 8'd64; 3'h7:decodeArsize <= 8'd128; default:decodeArsize <= 8'd1; endcase end always@ (posedge axi_aclk) begin if(axi_arvalid) araddrReg <= axi_araddr; else if (rEnable && axi_rready) begin case(arburstReg) 2'b00://fixed burst araddrReg <= araddrReg; 2'b01://incremental burst araddrReg <= araddrReg + decodeArsize; 2'b10://wrap burst begin if(arWrap) araddrReg <= araddrReg - arWrapSize; else araddrReg <= araddrReg + decodeArsize; end default: araddrReg <= araddrReg; endcase end end // R Operation assign axi_rdata = data_o; // R Response assign axi_rvalid = busRead? |rvalid : 1'b0 ; assign axi_rlast = busRead? |rlast : 1'b0 ; assign axi_rresp = 2'b00; assign axi_rid = aridReg; //custom logic starts here assign axi_interrupt = r_axi_interrupt; assign rEnable = (axi_arburst == 2'b10)? busRead : busPreRead; always@ (posedge axi_aclk) begin if (!axi_resetn) begin r_axi_interrupt <= 1'b0; end else begin if((axi_wvalid) && (axi_wdata == 16'hABCD)) r_axi_interrupt <= 1'b1; else r_axi_interrupt <= 1'b0; end end genvar i; generate for(i=0;i < (DATA_WIDTH/8); i = i + 1) begin assign rvalid[i] = (arlenReg != 'h1)? rdata[i][8] : 1'b1; assign rlast[i] = (arlenReg != 'h1)? rdata[i][9] : 1'b1; assign wdata[i] = {axi_wlast, axi_wvalid, axi_wdata[(i*8+7) -: 8]} ; assign data_o[(i*8+7) -: 8] = rdata[i]; assign wEnable[i] = axi_wready & axi_wvalid & axi_wstrb[i]; ext_mem #( .DATA_WIDTH (10), .ADDR_WIDTH (RAMW-2), .OUTPUT_REG ("TRUE") ) user_ram ( .wdata (wdata[i]), .waddr (awaddrReg[RAMW-1:2]), .raddr (araddrReg[RAMW-1:2]), .we (wEnable[i]), .wclk (axi_aclk), .re (rEnable), .rclk (axi_aclk), .rdata (rdata[i]) ); end endgenerate endmodule // *********************************************************************** module memory_checker #( parameter WIDTH = 32, parameter ALEN = 23, parameter START_ADDR = 32'h00000000, parameter STOP_ADDR = 32'h00100000, parameter ADDR_OFFSET = (ALEN + 1)*(WIDTH/8) ) ( input axi_clk, input rstn, input start, output [7:0] aid, output reg [31:0] aaddr, output reg [7:0] alen, output reg [2:0] asize, output reg [1:0] aburst, output reg [1:0] alock, output reg avalid, input aready, output reg atype, output [7:0] wid, output reg [WIDTH-1:0] wdata, output [WIDTH/8-1:0] wstrb, output reg wlast, output reg wvalid, input wready, input [3:0] rid, input [WIDTH-1:0] rdata, input rlast, input rvalid, output reg rready, input [1:0] rresp, input [7:0] bid, input bvalid, output reg bready, output pass ); /////////////////////////////////////////////////////////////////////////////// localparam ASIZE = (WIDTH == 512)? 6 : (WIDTH == 256)? 5 : (WIDTH == 128)? 4 : (WIDTH == 64)? 3 : 2; //Main states localparam COMPARE_WIDTH = WIDTH; localparam IDLE = 4'b0000, WRITE_ADDR = 4'b0001, PRE_WRITE = 4'b0010, WRITE = 4'b0011, POST_WRITE = 4'b0100, READ_ADDR = 4'b0101, PRE_READ = 4'b0110, READ_COMPARE = 4'b0111, POST_READ = 4'b1000, DONE = 4'b1001; //reg [3:0] states, nstates; reg fail; reg done; reg [3:0] states; reg [3:0] nstates; reg bvalid_done; reg [1:0] start_sync; reg [8:0] write_cnt, read_cnt; reg [WIDTH-1:0] rdata_store; reg wburst_done, rburst_done, write_done, read_done; /////////////////////////////////////////////////////////////////////////////// assign aid = 8'h00; assign wstrb = {WIDTH/8{1'b1}}; assign wid = 8'h00; assign pass = done & ~fail; always @(posedge axi_clk or negedge rstn) begin if (!rstn) begin start_sync <= 2'b00; end else begin start_sync[0] <= start; start_sync[1] <= start_sync[0]; end end always @(posedge axi_clk or negedge rstn) begin if (!rstn) begin states <= IDLE; end else begin states <= nstates; end end always @(states or start_sync[1] or write_cnt or rburst_done or write_done or read_done or bvalid_done or aready) begin case(states) IDLE : if (start_sync[1]) nstates = WRITE_ADDR; else nstates = IDLE; WRITE_ADDR : if (aready) nstates = PRE_WRITE; else nstates = WRITE_ADDR; PRE_WRITE : nstates = WRITE; WRITE : if (write_cnt == 9'd0) nstates = POST_WRITE; else nstates = WRITE; POST_WRITE : if (write_done & bvalid_done) nstates = READ_ADDR; else if (bvalid_done) nstates = WRITE_ADDR; else nstates = POST_WRITE; READ_ADDR : if (aready) nstates = PRE_READ; else nstates = READ_ADDR; PRE_READ : nstates = READ_COMPARE; READ_COMPARE : if (rburst_done) nstates = POST_READ; else nstates = READ_COMPARE; POST_READ : if (read_done) nstates = DONE; else nstates = READ_ADDR; DONE : nstates = DONE; default : nstates = IDLE; endcase end always @(posedge axi_clk or negedge rstn) begin if (!rstn) begin aaddr <= START_ADDR; avalid <= 1'b0; atype <= 1'b0; aburst <= 2'b00; asize <= 3'b000; alen <= 8'd0; alock <= 2'b00; wvalid <= 1'b0; write_cnt <= ALEN + 1; write_done <= 1'b0; wdata <= {WIDTH{1'b0}}; wburst_done <= 1'b0; wlast <= 1'b0; bready <= 1'b0; fail <= 1'b0; done <= 1'b0; rready <= 1'b0; bvalid_done <=1'b0; end else begin if (states == IDLE) begin aaddr <= START_ADDR; avalid <= 1'b0; atype <= 1'b0; aburst <= 2'b00; asize <= 3'b000; alen <= 8'd0; alock <= 2'b00; wvalid <= 1'b0; write_cnt <= ALEN + 1; wdata <= {WIDTH{1'b0}}; wburst_done <= 1'b0; wlast <= 1'b0; bready <= 1'b0; rready <= 1'b0; bvalid_done <= 1'b0; fail <= 1'b0; done <= 1'b0; end if (states == WRITE_ADDR) begin avalid <= 1'b1; atype <= 1'b1; asize <= ASIZE; alen <= ALEN; aburst <= 2'b01; alock <= 2'b00; wvalid <= 1'b0; write_cnt <= ALEN + 1; wburst_done <= 1'b0; bvalid_done <= 1'b0; bready <= 1'b0; rready <= 1'b0; done <= 1'b0; fail <= 1'b0; end if (states == PRE_WRITE) begin avalid <= 1'b0; atype <= 1'b0; wvalid <= 1'b1; wdata <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~write_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{write_cnt[7:0]}}}; bready <= 1'b1; write_cnt <= write_cnt - 1; if(alen == 'd0) begin wlast <= 1'b1; end end if (states == WRITE) begin if (wready == 1'b1) begin wdata <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~write_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{write_cnt[7:0]}}}; if (write_cnt == 9'd0) begin wburst_done <= 1'b1; wlast <= 1'b0; wvalid <= 1'b0; if (aaddr >= STOP_ADDR) begin write_done <= 1'b1; end else begin write_done <= 1'b0; end end if (write_cnt == 9'd1) begin wlast <= 1'b1; write_cnt <= write_cnt - 1; end else begin write_cnt <= write_cnt - 1; end end end if (states == POST_WRITE) begin if (write_done) begin aaddr <= START_ADDR; end else begin if (bvalid) begin aaddr <= aaddr + ADDR_OFFSET; end end if (wready == 1'b1) begin wlast <= 1'b0; wvalid <= 1'b0; end if (bvalid) begin bvalid_done <= 1'b1; bready <= 1'b0; end end if (states == READ_ADDR) begin avalid <= 1'b1; read_cnt <= ALEN + 1; end if (states == PRE_READ) begin avalid <= 1'b0; rburst_done <= 1'b0; rdata_store <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~read_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{read_cnt[7:0]}}}; read_cnt <= read_cnt - 1'b1; end if (states == READ_COMPARE) begin rready <= 1'b1; if (read_cnt != 9'd0) begin if (rvalid == 1'b1) begin rdata_store <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~read_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{read_cnt[7:0]}}}; read_cnt <= read_cnt - 1'b1; if (rdata[COMPARE_WIDTH-1:0] != rdata_store[COMPARE_WIDTH-1:0]) fail <= 1'b1; else fail <= 1'b0; end end end if (read_cnt == 9'd0) begin if (rvalid == 1'b1) begin if (rdata[COMPARE_WIDTH-1:0] != rdata_store[COMPARE_WIDTH-1:0]) begin fail <= 1'b1; end else begin fail <= 1'b0; end if (aaddr >= STOP_ADDR) begin read_done <= 1'b1; end else begin read_done <= 1'b0; end rburst_done <= 1'b1; end end if (states == POST_READ) begin aaddr <= aaddr + ADDR_OFFSET; rready <= 1'b1; end if (states == DONE) begin done <= 1'b1; end end end endmodule // *********************************************************************** module timer_start #( parameter MHZ = 50, parameter SECOND = 3, parameter PULSE = 0 ) ( input clk, input rst_n, output start ); reg [35:0] delay_cnt; wire second_tick; reg [4:0] second_cnt; reg [3:0] pulse_reg; wire start_reg; /////////////////////////////////////////////////////////////////////////////// `ifndef EFX_SIM localparam tick_cnt = (MHZ * 1000000) >> 1; `else localparam tick_cnt = MHZ * 200; `endif always@(posedge clk or negedge rst_n) begin if(!rst_n) delay_cnt <= 'd0; else begin if(delay_cnt == tick_cnt || start_reg == 1'b1) delay_cnt <= 'd0; else delay_cnt <= delay_cnt + 1'b1; end end assign second_tick = ((delay_cnt) == (tick_cnt - 1)); always@(posedge clk or negedge rst_n) begin if(!rst_n) second_cnt <= 'd0; else begin if(second_tick) second_cnt <= second_cnt + 1'b1; else second_cnt <= second_cnt; end end assign start_reg = (second_cnt == SECOND); always@(posedge clk) begin pulse_reg <= {pulse_reg[2:0],start_reg}; end generate if(PULSE == 1) assign start = ~pulse_reg[3] & start_reg; else assign start = start_reg; endgenerate endmodule // *********************************************************************** module ext_mem #( parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 9, parameter OUTPUT_REG = "TRUE", parameter RAM_INIT_FILE = "" ) ( input [DATA_WIDTH-1:0] wdata, input [ADDR_WIDTH-1:0] waddr, input [ADDR_WIDTH-1:0] raddr, input we, input wclk, input re, input rclk, output [DATA_WIDTH-1:0] rdata ); ///////////////////////////////////////////////////////////////////////////// localparam MEMORY_DEPTH = 2**ADDR_WIDTH; localparam MAX_DATA = (1<