raster simulate
This commit is contained in:
parent
013774e28b
commit
96e9a3d043
|
@ -3,7 +3,7 @@
|
||||||
.PHONY: test clean
|
.PHONY: test clean
|
||||||
|
|
||||||
|
|
||||||
test: obj_dir/Vram_fifo obj_dir/Vram_shim
|
test: obj_dir/Vram_fifo obj_dir/Vram_shim obj_dir/Vraster_sim
|
||||||
|
|
||||||
RAM_FIFO_SRC= ram_fifo.v ram_fifo_dual_port.v ram_fifo_sim.cpp
|
RAM_FIFO_SRC= ram_fifo.v ram_fifo_dual_port.v ram_fifo_sim.cpp
|
||||||
obj_dir/Vram_fifo.mk: ${RAM_FIFO_SRC}
|
obj_dir/Vram_fifo.mk: ${RAM_FIFO_SRC}
|
||||||
|
@ -11,7 +11,7 @@ obj_dir/Vram_fifo.mk: ${RAM_FIFO_SRC}
|
||||||
${RAM_FIFO_SRC}
|
${RAM_FIFO_SRC}
|
||||||
obj_dir/Vram_fifo: obj_dir/Vram_fifo.mk
|
obj_dir/Vram_fifo: obj_dir/Vram_fifo.mk
|
||||||
cd obj_dir && make -f Vram_fifo.mk
|
cd obj_dir && make -f Vram_fifo.mk
|
||||||
@./obj_dir/Vram_fifo && echo 'Vram_fifo successful'
|
@./obj_dir/Vram_fifo && echo 'ram_fifo successful'
|
||||||
|
|
||||||
RAM_SHIM_SRC= ram_shim.v ram_fifo.v ram_fifo_dual_port.v ram_shim_sim.cpp
|
RAM_SHIM_SRC= ram_shim.v ram_fifo.v ram_fifo_dual_port.v ram_shim_sim.cpp
|
||||||
obj_dir/Vram_shim.mk: ${RAM_SHIM_SRC} ram_shim_cmds.vh ram_shim_cmds.h
|
obj_dir/Vram_shim.mk: ${RAM_SHIM_SRC} ram_shim_cmds.vh ram_shim_cmds.h
|
||||||
|
@ -20,14 +20,26 @@ obj_dir/Vram_shim.mk: ${RAM_SHIM_SRC} ram_shim_cmds.vh ram_shim_cmds.h
|
||||||
${RAM_SHIM_SRC}
|
${RAM_SHIM_SRC}
|
||||||
obj_dir/Vram_shim: obj_dir/Vram_shim.mk ram_shim_sim.cpp
|
obj_dir/Vram_shim: obj_dir/Vram_shim.mk ram_shim_sim.cpp
|
||||||
cd obj_dir && make -f Vram_shim.mk
|
cd obj_dir && make -f Vram_shim.mk
|
||||||
@./obj_dir/Vram_shim && echo 'Vram_shim successful'
|
@./obj_dir/Vram_shim && echo 'ram_shim successful'
|
||||||
|
|
||||||
|
RASTER_SIM_SRC = raster_sim.v raster.v ram_shim.v ram_fifo.v ram_fifo_dual_port.v raster_sim.cpp
|
||||||
|
|
||||||
|
obj_dir/Vraster_sim.mk: ${RASTER_SIM_SRC} raster_cmds.vh raster_cmds.h ram_shim_cmds.vh ram_shim_cmds.h
|
||||||
|
verilator --cc --exe -Wall --trace --trace-fst -CFLAGS -Wall \
|
||||||
|
${RASTER_SIM_SRC}
|
||||||
|
obj_dir/Vraster_sim: obj_dir/Vraster_sim.mk raster_sim.cpp
|
||||||
|
cd obj_dir && make -f Vraster_sim.mk
|
||||||
|
@./obj_dir/Vraster_sim && echo 'raster successful'
|
||||||
|
|
||||||
####### Codegen ########
|
####### Codegen ########
|
||||||
|
|
||||||
ram_shim_cmds.h: ram_shim_cmds.vh
|
ram_shim_cmds.h: ram_shim_cmds.vh
|
||||||
echo '#pragma once' > ram_shim_cmds.h
|
echo '#pragma once' > ram_shim_cmds.h
|
||||||
sed 's/`define/#define/g; s/`//g' ram_shim_cmds.vh >> ram_shim_cmds.h
|
sed 's/`define/#define/g; s/`//g' ram_shim_cmds.vh >> ram_shim_cmds.h
|
||||||
|
raster_cmds.h: raster_cmds.vh
|
||||||
|
echo '#pragma once' > raster_cmds.h
|
||||||
|
sed 's/`define/#define/g; s/`//g' raster_cmds.vh >> raster_cmds.h
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf obj_dir
|
rm -rf obj_dir
|
||||||
rm *.vcd ram_shim_cmds.h
|
rm -f *.vcd ram_shim_cmds.h
|
||||||
|
|
|
@ -8,50 +8,50 @@
|
||||||
`include "raster_cmds.vh"
|
`include "raster_cmds.vh"
|
||||||
`timescale 10ns/10ns
|
`timescale 10ns/10ns
|
||||||
module raster #(
|
module raster #(
|
||||||
parameter SAMPLEWID = 9,
|
parameter DAC_WAIT_BETWEEN_CMD = 10
|
||||||
parameter DAC_DATA_WID = 20,
|
|
||||||
parameter DAC_WID = 24,
|
|
||||||
parameter DAC_WAIT_BETWEEN_CMD = 10,
|
|
||||||
parameter TIMER_WID = 4,
|
|
||||||
parameter STEPWID = 16,
|
|
||||||
parameter ADCNUM = 9,
|
|
||||||
parameter MAX_ADC_DATA_WID = 24
|
|
||||||
) (
|
) (
|
||||||
input clk,
|
input clk,
|
||||||
|
`ifdef VERILATOR
|
||||||
|
output is_running,
|
||||||
|
`endif
|
||||||
|
|
||||||
/* Kernel interface. */
|
/* Kernel interface. */
|
||||||
input [`RASTER_CMD_WID-1:0] kernel_cmd,
|
input [`RASTER_CMD_WID-1:0] kernel_cmd,
|
||||||
|
/* verilator lint_off UNUSEDSIGNAL */
|
||||||
input [`RASTER_DATA_WID-1:0] kernel_data_in,
|
input [`RASTER_DATA_WID-1:0] kernel_data_in,
|
||||||
|
/* verilator lint_on UNUSEDSIGNAL */
|
||||||
output reg [`RASTER_DATA_WID-1:0] kernel_data_out,
|
output reg [`RASTER_DATA_WID-1:0] kernel_data_out,
|
||||||
input kernel_ready,
|
input kernel_ready,
|
||||||
output reg kernel_finished,
|
output reg kernel_finished,
|
||||||
|
|
||||||
/* X and Y DAC piezos */
|
/* X and Y DAC piezos */
|
||||||
output x_arm,
|
output x_arm,
|
||||||
output [DAC_WID-1:0] x_to_dac,
|
output [`DAC_WID-1:0] x_to_dac,
|
||||||
/* verilator lint_off UNUSED */
|
/* verilator lint_off UNUSED */
|
||||||
input [DAC_WID-1:0] x_from_dac,
|
input [`DAC_WID-1:0] x_from_dac,
|
||||||
|
/* verilator lint_on UNUSED */
|
||||||
input x_finished,
|
input x_finished,
|
||||||
|
|
||||||
output y_arm,
|
output y_arm,
|
||||||
output [DAC_WID-1:0] y_to_dac,
|
output [`DAC_WID-1:0] y_to_dac,
|
||||||
/* verilator lint_off UNUSED */
|
/* verilator lint_off UNUSED */
|
||||||
input [DAC_WID-1:0] y_from_dac,
|
input [`DAC_WID-1:0] y_from_dac,
|
||||||
|
/* verilator lint_on UNUSED */
|
||||||
input y_finished,
|
input y_finished,
|
||||||
|
|
||||||
/* Connections to all possible ADCs. These are connected to SPI masters
|
/* Connections to all possible ADCs. These are connected to SPI masters
|
||||||
* and they will automatically extend ADC value lengths to their highest
|
* and they will automatically extend ADC value lengths to their highest
|
||||||
* values. */
|
* values. */
|
||||||
output reg [ADCNUM-1:0] adc_arm,
|
output reg [`ADCNUM-1:0] adc_arm,
|
||||||
|
|
||||||
/* Yosys does not support input arrays. */
|
/* Yosys does not support input arrays. */
|
||||||
input [ADCNUM*MAX_ADC_DATA_WID-1:0] adc_data,
|
input [`ADCNUM*`MAX_ADC_DATA_WID-1:0] adc_data,
|
||||||
input [ADCNUM-1:0] adc_finished,
|
input [`ADCNUM-1:0] adc_finished,
|
||||||
|
|
||||||
/* RAM DMA. This is generally not directly connected to the
|
/* RAM DMA. This is generally not directly connected to the
|
||||||
* DMA IP. A shim is used in order to write multiple words
|
* DMA IP. A shim is used in order to write multiple words
|
||||||
* to memory. */
|
* to memory. */
|
||||||
output reg [MAX_ADC_DATA_WID-1:0] data,
|
output reg [`MAX_ADC_DATA_WID-1:0] data,
|
||||||
output reg mem_commit,
|
output reg mem_commit,
|
||||||
input mem_finished
|
input mem_finished
|
||||||
);
|
);
|
||||||
|
@ -101,43 +101,45 @@ module raster #(
|
||||||
*/
|
*/
|
||||||
|
|
||||||
localparam WAIT_ON_ARM = 0;
|
localparam WAIT_ON_ARM = 0;
|
||||||
localparam GET_DAC_VALUES = 1;
|
localparam REQUEST_DAC_VALUES = 1;
|
||||||
localparam REQUEST_DAC_VALUES = 2;
|
localparam GET_DAC_VALUES = 2;
|
||||||
localparam MEASURE = 3;
|
localparam WAIT_ADVANCE = 3;
|
||||||
localparam SCAN_ADC_VALUES = 4;
|
localparam MEASURE = 4;
|
||||||
localparam ADVANCE_DAC_WRITE = 5;
|
localparam SCAN_ADC_VALUES = 5;
|
||||||
localparam WAIT_ADVANCE = 6;
|
localparam ADVANCE_DAC_WRITE = 6;
|
||||||
localparam NEXT_LINE = 7;
|
localparam NEXT_LINE = 7;
|
||||||
localparam WAIT_ON_ARM_DEASSERT = 8;
|
localparam WAIT_ON_ARM_DEASSERT = 8;
|
||||||
localparam STATE_WID = 4;
|
localparam STATE_WID = 4;
|
||||||
|
|
||||||
/********** Loop State ***********/
|
/********** Loop State ***********/
|
||||||
reg [STATE_WID-1:0] state = WAIT_ON_ARM;
|
reg [STATE_WID-1:0] state = WAIT_ON_ARM;
|
||||||
reg [SAMPLEWID-1:0] sample = 0;
|
reg [`SAMPLEWID-1:0] sample = 0;
|
||||||
reg [SAMPLEWID-1:0] line = 0;
|
reg [`SAMPLEWID-1:0] line = 0;
|
||||||
reg [TIMER_WID-1:0] counter = 0;
|
reg [`TIMERWID-1:0] counter = 0;
|
||||||
reg signed [DAC_DATA_WID-1:0] x_val = 0;
|
reg signed [`DAC_DATA_WID-1:0] x_val = 0;
|
||||||
reg signed [DAC_DATA_WID-1:0] y_val = 0;
|
reg signed [`DAC_DATA_WID-1:0] y_val = 0;
|
||||||
|
|
||||||
/* Buffer to store all measured ADC values. This
|
/* Buffer to store all measured ADC values. This
|
||||||
* is shifted until it is all zeros to determine
|
* is shifted until it is all zeros to determine
|
||||||
* which ADC values should be read off.
|
* which ADC values should be read off.
|
||||||
*/
|
*/
|
||||||
reg [ADCNUM-1:0] adc_used_tmp = 0;
|
reg [`ADCNUM-1:0] adc_used_tmp = 0;
|
||||||
reg [ADCNUM*MAX_ADC_DATA_WID-1:0] adc_data_tmp = 0;
|
reg [`ADCNUM*`MAX_ADC_DATA_WID-1:0] adc_data_tmp = 0;
|
||||||
|
|
||||||
/********** Loop Parameters *************/
|
/********** Loop Parameters *************/
|
||||||
reg [ADCNUM-1:0] adc_used = 0;
|
reg [`ADCNUM-1:0] adc_used = 0;
|
||||||
reg is_reverse = 0;
|
reg is_reverse = 0;
|
||||||
reg arm = 0;
|
reg arm = 0;
|
||||||
reg running = 0;
|
reg running = 0;
|
||||||
reg signed [DAC_DATA_WID-1:0] dx = 0;
|
`ifdef VERILATOR
|
||||||
reg signed [DAC_DATA_WID-1:0] dy = 0;
|
assign is_running = running;
|
||||||
reg [TIMER_WID-1:0] settle_time = 0;
|
`endif
|
||||||
|
reg signed [`DAC_DATA_WID-1:0] dx = 0;
|
||||||
|
reg signed [`DAC_DATA_WID-1:0] dy = 0;
|
||||||
|
reg [`TIMERWID-1:0] settle_time = 0;
|
||||||
|
|
||||||
reg [SAMPLEWID-1:0] max_samples = 0;
|
reg [`SAMPLEWID-1:0] max_samples = 0;
|
||||||
reg [SAMPLEWID-1:0] max_lines = 0;
|
reg [`SAMPLEWID-1:0] max_lines = 0;
|
||||||
reg [STEPWID-1:0] steps_per_sample = 0;
|
|
||||||
|
|
||||||
/********** Control Interface ************
|
/********** Control Interface ************
|
||||||
* This code assumes that RASTER_DATA_WID is greater than all registers.
|
* This code assumes that RASTER_DATA_WID is greater than all registers.
|
||||||
|
@ -161,25 +163,26 @@ end
|
||||||
// Generates code to handle write requests from the kernel.
|
// Generates code to handle write requests from the kernel.
|
||||||
`define generate_register(code, width, register) \
|
`define generate_register(code, width, register) \
|
||||||
`generate_register_read(code, width, register) \
|
`generate_register_read(code, width, register) \
|
||||||
code | `RASTER_WRITE_BIT: begin \
|
code | `RASTER_WRITE_BIT: \
|
||||||
if (!running && (code) != `RASTER_ARM) begin \
|
if (!running || (code) == `RASTER_ARM) begin \
|
||||||
register <= kernel_data_in[(width)-1:0]; \
|
register <= kernel_data_in[(width)-1:0]; \
|
||||||
kernel_finished <= 1; \
|
kernel_finished <= 1; \
|
||||||
end \
|
end
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
always @ (posedge clk) begin
|
||||||
if (!kernel_ready) kernel_finished <= 0;
|
if (!kernel_ready) kernel_finished <= 0;
|
||||||
else if (kernel_ready) begin case (kernel_cmd)
|
else if (kernel_ready) begin case (kernel_cmd)
|
||||||
`generate_register(`RASTER_MAX_SAMPLES, SAMPLEWID, max_samples)
|
`generate_register(`RASTER_MAX_SAMPLES, `SAMPLEWID, max_samples)
|
||||||
`generate_register(`RASTER_MAX_LINES, SAMPLEWID, max_lines)
|
`generate_register(`RASTER_MAX_LINES, `SAMPLEWID, max_lines)
|
||||||
`generate_register(`RASTER_SETTLE_TIME, TIMER_WID, settle_time)
|
`generate_register(`RASTER_SETTLE_TIME, `TIMERWID, settle_time)
|
||||||
`generate_register(`RASTER_DX, DAC_DATA_WID, dx)
|
`generate_register(`RASTER_DX, `DAC_DATA_WID, dx)
|
||||||
`generate_register(`RASTER_DY, DAC_DATA_WID, dy)
|
`generate_register(`RASTER_DY, `DAC_DATA_WID, dy)
|
||||||
`generate_register(`RASTER_USED_ADCS, ADCNUM, adc_used)
|
`generate_register(`RASTER_USED_ADCS, `ADCNUM, adc_used)
|
||||||
`generate_register(`RASTER_STEPS_PER_SAMPLE, STEPWID, steps_per_sample)
|
|
||||||
`generate_register(`RASTER_ARM, 1, arm)
|
`generate_register(`RASTER_ARM, 1, arm)
|
||||||
`generate_register_read(`RASTER_RUNNING, 1, running)
|
`generate_register_read(`RASTER_RUNNING, 1, running)
|
||||||
|
`ifdef VERILATOR
|
||||||
|
default: $error("unknown kernel message");
|
||||||
|
`endif
|
||||||
endcase end
|
endcase end
|
||||||
end
|
end
|
||||||
`undef generate_register_read
|
`undef generate_register_read
|
||||||
|
@ -234,8 +237,8 @@ always @ (posedge clk) begin
|
||||||
x_arm <= 1;
|
x_arm <= 1;
|
||||||
y_arm <= 1;
|
y_arm <= 1;
|
||||||
end else if (x_finished && y_finished) begin
|
end else if (x_finished && y_finished) begin
|
||||||
x_val <= x_from_dac[DAC_DATA_WID-1:0];
|
x_val <= x_from_dac[`DAC_DATA_WID-1:0];
|
||||||
y_val <= y_from_dac[DAC_DATA_WID-1:0];
|
y_val <= y_from_dac[`DAC_DATA_WID-1:0];
|
||||||
|
|
||||||
x_arm <= 0;
|
x_arm <= 0;
|
||||||
y_arm <= 0;
|
y_arm <= 0;
|
||||||
|
@ -262,7 +265,7 @@ always @ (posedge clk) begin
|
||||||
end
|
end
|
||||||
SCAN_ADC_VALUES: if (adc_used_tmp == 0 && !mem_commit) begin
|
SCAN_ADC_VALUES: if (adc_used_tmp == 0 && !mem_commit) begin
|
||||||
`CHECK_DAC_ARM
|
`CHECK_DAC_ARM
|
||||||
if (sample == max_samples) begin
|
if (sample == max_samples-1) begin
|
||||||
dx <= ~dx + 1;
|
dx <= ~dx + 1;
|
||||||
dy <= ~dy + 1;
|
dy <= ~dy + 1;
|
||||||
|
|
||||||
|
@ -275,6 +278,7 @@ always @ (posedge clk) begin
|
||||||
is_reverse <= !is_reverse;
|
is_reverse <= !is_reverse;
|
||||||
sample <= 0;
|
sample <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
|
sample <= sample + 1;
|
||||||
state <= ADVANCE_DAC_WRITE;
|
state <= ADVANCE_DAC_WRITE;
|
||||||
end
|
end
|
||||||
end else if (mem_finished) begin
|
end else if (mem_finished) begin
|
||||||
|
@ -284,9 +288,9 @@ always @ (posedge clk) begin
|
||||||
end else begin
|
end else begin
|
||||||
`CHECK_DAC_ARM
|
`CHECK_DAC_ARM
|
||||||
adc_used_tmp <= adc_used_tmp << 1;
|
adc_used_tmp <= adc_used_tmp << 1;
|
||||||
adc_data_tmp <= adc_data_tmp << MAX_ADC_DATA_WID;
|
adc_data_tmp <= adc_data_tmp << `MAX_ADC_DATA_WID;
|
||||||
if (adc_used_tmp[ADCNUM-1]) begin
|
if (adc_used_tmp[`ADCNUM-1]) begin
|
||||||
data <= adc_data_tmp[ADCNUM*MAX_ADC_DATA_WID-1:(ADCNUM-1)*MAX_ADC_DATA_WID];
|
data <= adc_data_tmp[`ADCNUM*`MAX_ADC_DATA_WID-1:(`ADCNUM-1)*`MAX_ADC_DATA_WID];
|
||||||
mem_commit <= 1;
|
mem_commit <= 1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -298,7 +302,6 @@ always @ (posedge clk) begin
|
||||||
y_to_dac <= {4'b0001, y_val + dy};
|
y_to_dac <= {4'b0001, y_val + dy};
|
||||||
x_arm <= 1;
|
x_arm <= 1;
|
||||||
y_arm <= 1;
|
y_arm <= 1;
|
||||||
sample <= sample + 1;
|
|
||||||
end else if (x_finished && y_finished) begin
|
end else if (x_finished && y_finished) begin
|
||||||
counter <= 0;
|
counter <= 0;
|
||||||
state <= WAIT_ADVANCE;
|
state <= WAIT_ADVANCE;
|
||||||
|
@ -306,10 +309,10 @@ always @ (posedge clk) begin
|
||||||
y_arm <= 0;
|
y_arm <= 0;
|
||||||
end
|
end
|
||||||
NEXT_LINE: if (!x_arm || !y_arm) begin
|
NEXT_LINE: if (!x_arm || !y_arm) begin
|
||||||
if (line == max_lines) begin
|
if (line == max_lines-1) begin
|
||||||
state <= WAIT_ON_ARM_DEASSERT;
|
state <= WAIT_ON_ARM_DEASSERT;
|
||||||
running <= 0;
|
|
||||||
end else begin
|
end else begin
|
||||||
|
sample <= 0;
|
||||||
/* rotation of (dx,dy) by 90° -> (dy, -dx) */
|
/* rotation of (dx,dy) by 90° -> (dy, -dx) */
|
||||||
x_val <= x_val + dy;
|
x_val <= x_val + dy;
|
||||||
x_to_dac <= {4'b0001, x_val + dy};
|
x_to_dac <= {4'b0001, x_val + dy};
|
||||||
|
@ -327,6 +330,8 @@ always @ (posedge clk) begin
|
||||||
end
|
end
|
||||||
WAIT_ON_ARM_DEASSERT: if (!arm) begin
|
WAIT_ON_ARM_DEASSERT: if (!arm) begin
|
||||||
state <= WAIT_ON_ARM;
|
state <= WAIT_ON_ARM;
|
||||||
|
end else begin
|
||||||
|
running <= 0;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
/* Make sure there are no gaps! The code generator will not work
|
|
||||||
* correctly.
|
|
||||||
*/
|
|
||||||
`define RASTER_NOOP 0
|
`define RASTER_NOOP 0
|
||||||
`define RASTER_MAX_SAMPLES 1
|
`define RASTER_MAX_SAMPLES 1
|
||||||
`define RASTER_MAX_LINES 2
|
`define RASTER_MAX_LINES 2
|
||||||
|
@ -9,11 +6,20 @@
|
||||||
`define RASTER_DY 5
|
`define RASTER_DY 5
|
||||||
`define RASTER_ARM 6
|
`define RASTER_ARM 6
|
||||||
`define RASTER_USED_ADCS 7
|
`define RASTER_USED_ADCS 7
|
||||||
`define RASTER_STEPS_PER_SAMPLE 8
|
`define RASTER_RUNNING 8
|
||||||
`define RASTER_RUNNING 9
|
|
||||||
|
|
||||||
`define RASTER_WRITE_BIT (1 << (`RASTER_CMD_WID - 1))
|
`define RASTER_WRITE_BIT (1 << (`RASTER_CMD_WID - 1))
|
||||||
|
|
||||||
`define RASTER_CMD_WID 8
|
`define RASTER_CMD_WID 8
|
||||||
|
|
||||||
`define RASTER_DATA_WID 32
|
`define RASTER_DATA_WID 32
|
||||||
|
|
||||||
|
/* Instead of using parameters, these values are preprocessor
|
||||||
|
* defines so that they may be reference in kernel code.
|
||||||
|
*/
|
||||||
|
`define SAMPLEWID 16
|
||||||
|
`define DAC_DATA_WID 20
|
||||||
|
`define DAC_WID 24
|
||||||
|
`define TIMERWID 8
|
||||||
|
`define ADCNUM 9
|
||||||
|
`define MAX_ADC_DATA_WID 24
|
||||||
|
|
|
@ -1,25 +1,57 @@
|
||||||
#include <memory>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstdarg>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <random>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <verilated.h>
|
#include <verilated.h>
|
||||||
|
|
||||||
|
#include "ram_shim_cmds.h"
|
||||||
|
#include "raster_cmds.h"
|
||||||
#include "Vraster_sim.h"
|
#include "Vraster_sim.h"
|
||||||
using ModType = Vraster_sim;
|
using ModType = Vraster_sim;
|
||||||
ModType *mod;
|
ModType *mod;
|
||||||
|
|
||||||
uint32_t main_time = 0;
|
uint32_t main_time = 0;
|
||||||
|
|
||||||
|
double sc_time_stamp() {
|
||||||
|
return main_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _assert(const char *file, int line, const char *exp, bool ev, const char *fmt, ...) {
|
||||||
|
if (!ev) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
fprintf(stderr, "%s:%d: assertion failed: %s\n", file, line, exp);
|
||||||
|
vfprintf(stderr, fmt, va);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(va);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STRINGIFY(s) #s
|
||||||
|
/* ,##__VA_ARGS__ is a GNU C extension */
|
||||||
|
#define my_assert(e, fmt, ...) _assert(__FILE__, __LINE__, STRINGIFY(e), (e), fmt ,##__VA_ARGS__)
|
||||||
|
|
||||||
static void run_clock() {
|
static void run_clock() {
|
||||||
|
#ifdef BAILOUT
|
||||||
|
static int iters = 0;
|
||||||
|
#endif
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
mod->clk = !mod->clk;
|
mod->clk = !mod->clk;
|
||||||
mod->eval();
|
mod->eval();
|
||||||
main_time++;
|
main_time++;
|
||||||
|
#ifdef BAILOUT
|
||||||
|
iters++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BAILOUT
|
||||||
|
if (iters >= 1000000)
|
||||||
|
exit(2);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanup_exit() {
|
static void cleanup_exit() {
|
||||||
|
@ -33,76 +65,171 @@ static void init(int argc, char **argv) {
|
||||||
mod = new ModType;
|
mod = new ModType;
|
||||||
mod->clk = 0;
|
mod->clk = 0;
|
||||||
atexit(cleanup_exit);
|
atexit(cleanup_exit);
|
||||||
|
|
||||||
|
char *seed = getenv("RANDOM_SEED");
|
||||||
|
if (seed) {
|
||||||
|
unsigned long i = strtoul(seed, NULL, 10);
|
||||||
|
srand((unsigned int)i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using V = uint32_t;
|
||||||
|
|
||||||
|
// Verilator makes all ports unsigned, even when marked as signed in
|
||||||
|
// Verilog.
|
||||||
|
V sign_extend(V x, unsigned len, bool is_signed) {
|
||||||
|
if (!is_signed)
|
||||||
|
return x;
|
||||||
|
// if high bit is 1
|
||||||
|
if (x >> (len - 1) & 1) {
|
||||||
|
// This mask selects all bits below the highest bit.
|
||||||
|
// By inverting it, it selects the highest bit, and all
|
||||||
|
// higher bits that must be sign extended.
|
||||||
|
V mask = (1 << len) - 1;
|
||||||
|
// Set all high bits to 1. The mask has all bits lower
|
||||||
|
// than the highest bit 0, so the bits in "x" pass through.
|
||||||
|
return ~mask | x;
|
||||||
|
} else {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t read_raster_reg(int reg, unsigned siz, bool is_signed) {
|
||||||
|
mod->kernel_cmd = reg;
|
||||||
|
mod->kernel_ready = 1;
|
||||||
|
while (!mod->kernel_finished)
|
||||||
|
run_clock();
|
||||||
|
mod->kernel_ready = 0;
|
||||||
|
run_clock();
|
||||||
|
|
||||||
|
return sign_extend(mod->kernel_data_out, siz, is_signed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t write_raster_reg(int reg, unsigned siz, int32_t val, bool is_signed) {
|
||||||
|
int32_t oldval = read_raster_reg(reg, siz, is_signed);
|
||||||
|
|
||||||
|
mod->kernel_cmd = reg | RASTER_WRITE_BIT;
|
||||||
|
mod->kernel_data_in = val;
|
||||||
|
|
||||||
|
mod->kernel_ready = 1;
|
||||||
|
while (!mod->kernel_finished)
|
||||||
|
run_clock();
|
||||||
|
mod->kernel_ready = 0;
|
||||||
|
run_clock();
|
||||||
|
|
||||||
|
int32_t cval = read_raster_reg(reg, siz, is_signed);
|
||||||
|
my_assert(cval == val, "written value (%x) != read val (%x)\n", val, cval);
|
||||||
|
|
||||||
|
return oldval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_shim_cmd(unsigned cmd, uint32_t val) {
|
||||||
|
mod->shim_cmd = cmd;
|
||||||
|
mod->shim_cmd_data = val;
|
||||||
|
mod->shim_cmd_active = 1;
|
||||||
|
|
||||||
|
while (!mod->shim_cmd_finished)
|
||||||
|
run_clock();
|
||||||
|
mod->shim_cmd_active = 0;
|
||||||
|
run_clock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_shim_ptr() {
|
||||||
|
mod->shim_cmd = RAM_SHIM_READ_PTR;
|
||||||
|
mod->shim_cmd_active = 1;
|
||||||
|
|
||||||
|
while (!mod->shim_cmd_finished)
|
||||||
|
run_clock();
|
||||||
|
mod->shim_cmd_active = 0;
|
||||||
|
run_clock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SAMPLES_PER_LINE 16
|
||||||
|
#define NUM_OF_LINES 16
|
||||||
|
static size_t expected_store_index = 0;
|
||||||
|
|
||||||
static void init_values() {
|
static void init_values() {
|
||||||
mod->arm = 0;
|
|
||||||
mod->max_samples_in = 512;
|
|
||||||
mod->max_lines_in = 512;
|
|
||||||
/* Settle time is 1 μs */
|
|
||||||
mod->settle_time_in = 100;
|
|
||||||
|
|
||||||
mod->dx_in = 17;
|
|
||||||
mod->dy_in = 13;
|
|
||||||
mod->coord_dac[0] = 0;
|
|
||||||
mod->coord_dac[1] = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < ADCNUM; i++)
|
for (int i = 0; i < ADCNUM; i++)
|
||||||
mod->adc_data[i] = 0;
|
mod->adc_data[i] = 0;
|
||||||
mod->adc_finished = 0;
|
mod->adc_finished = 0;
|
||||||
mod->adc_used_in = 0;
|
|
||||||
|
|
||||||
mod->ram_valid = 0;
|
mod->ram_valid = 0;
|
||||||
|
|
||||||
|
my_assert(write_raster_reg(RASTER_MAX_SAMPLES, SAMPLEWID, SAMPLES_PER_LINE, false) == 0, "samples per line was not zero");
|
||||||
|
my_assert(write_raster_reg(RASTER_MAX_LINES, SAMPLEWID, NUM_OF_LINES, false) == 0, "max lines was not zero");
|
||||||
|
my_assert(write_raster_reg(RASTER_SETTLE_TIME, TIMERWID, 30, false) == 0, "settle time was not zero");
|
||||||
|
my_assert(write_raster_reg(RASTER_DX, DAC_DATA_WID, 12, true) == 0, "dx was not zero");
|
||||||
|
my_assert(write_raster_reg(RASTER_DY, DAC_DATA_WID, 12, true) == 0, "dy was not zero");
|
||||||
|
my_assert(write_raster_reg(RASTER_USED_ADCS, ADCNUM, 0b111101011, false) == 0, "adcnum was not zero");
|
||||||
|
expected_store_index = SAMPLES_PER_LINE * NUM_OF_LINES * 7 * 2;
|
||||||
|
|
||||||
|
write_shim_cmd(RAM_SHIM_WRITE_LOC, 0x10000);
|
||||||
|
write_shim_cmd(RAM_SHIM_WRITE_LEN, 0x0FFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *measured_values[ADCNUM];
|
// Forward and reverse, so multiply by 2
|
||||||
|
static std::array<int32_t, SAMPLES_PER_LINE * NUM_OF_LINES * ADCNUM*2> stored_values;
|
||||||
static void init_measurements() {
|
static size_t store_index = 0;
|
||||||
std::default_random_engine generator{};
|
static std::array<uint16_t, SAMPLES_PER_LINE * NUM_OF_LINES * ADCNUM*2*2> received_values;
|
||||||
std::normal_distribution<> dist{10000, 100};
|
static size_t pushed_index = 0;
|
||||||
std::random_device rd;
|
|
||||||
|
|
||||||
for (int i = 0; i < ADCNUM; i++) {
|
|
||||||
generator.seed(rd());
|
|
||||||
measured_values[i] = new int32_t[mod->max_lines_in][mod->max_samples_in];
|
|
||||||
for (int j = 0; j < mod->max_lines_in; j++) {
|
|
||||||
for (int k = 0; k < mod->max_samples_in; k++) {
|
|
||||||
measured_values[i][j][k] = dist(generator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void deinit_measurement() {
|
|
||||||
for (int i = 0; i < ADCNUM; i++) {
|
|
||||||
delete measured_values[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::array<uint16_t, 1 << MAX_BYTE_WID> fifo;
|
|
||||||
static uint32_t read_pos, write_pos;
|
|
||||||
|
|
||||||
static void handle_ram() {
|
static void handle_ram() {
|
||||||
|
if (mod->ram_write && !mod->ram_valid) {
|
||||||
|
my_assert(pushed_index < received_values.max_size(), "pushed_index (%zu) maxed out", pushed_index);
|
||||||
|
received_values[pushed_index++] = mod->word;
|
||||||
|
mod->ram_valid = 1;
|
||||||
|
} else if (!mod->ram_write) {
|
||||||
|
mod->ram_valid = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_adc() {
|
static void handle_adc() {
|
||||||
static int cntr[ADCNUM] = {0};
|
uint32_t tmp_adc_arm = mod->adc_arm;
|
||||||
static bool measuring[ADCNUM] = {0};
|
int i = 0;
|
||||||
|
static int amount_called = 0;
|
||||||
|
|
||||||
for (int i = 0; i < ADCNUM; i++) {
|
if (mod->adc_arm && mod->adc_arm != mod->adc_finished) {
|
||||||
if (mod->adc_used_in & 1) {
|
while (tmp_adc_arm) {
|
||||||
|
if (tmp_adc_arm & 1) {
|
||||||
|
my_assert(store_index < stored_values.max_size(),
|
||||||
|
"%d = %zu", store_index, stored_values.max_size());
|
||||||
|
uint32_t x = sign_extend(rand(), 24, false);
|
||||||
|
memcpy(&stored_values[store_index], &x, sizeof(x));
|
||||||
|
mod->adc_data[i] = stored_values[store_index];
|
||||||
|
store_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
tmp_adc_arm >>= 1;
|
||||||
|
}
|
||||||
|
mod->adc_finished = mod->adc_arm;
|
||||||
|
fprintf(stderr, "amount called: %d\n", ++amount_called);
|
||||||
|
} else if (!mod->adc_arm) {
|
||||||
|
mod->adc_finished = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
init(argc, argv);
|
init(argc, argv);
|
||||||
init_values();
|
init_values();
|
||||||
init_measurements();
|
|
||||||
run_clock();
|
run_clock();
|
||||||
|
|
||||||
mod->arm = 1;
|
write_raster_reg(RASTER_ARM, 1, 1, false);
|
||||||
while (!mod->finished) {
|
|
||||||
|
while (mod->is_running) {
|
||||||
run_clock();
|
run_clock();
|
||||||
handle_ram();
|
handle_ram();
|
||||||
|
handle_adc();
|
||||||
|
}
|
||||||
|
|
||||||
|
my_assert(pushed_index % 2 == 0, "uneven pushed index %d", pushed_index);
|
||||||
|
my_assert(store_index != pushed_index/2, "store_index (%d) != pushed_index/2(%d)\n", store_index, pushed_index/2);
|
||||||
|
my_assert(store_index == expected_store_index, "store_index (%zu) != (%zu)", store_index, expected_store_index);
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pushed_index; i += 2) {
|
||||||
|
int32_t calcval = received_values[i+1] << 16 | received_values[i];
|
||||||
|
my_assert(calcval == stored_values[i/2], "calcval = %x, stored_values = %x", calcval, stored_values[i/2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -2,23 +2,17 @@
|
||||||
`include "raster_cmds.vh"
|
`include "raster_cmds.vh"
|
||||||
`include "ram_shim_cmds.vh"
|
`include "ram_shim_cmds.vh"
|
||||||
module raster_sim #(
|
module raster_sim #(
|
||||||
parameter SAMPLEWID = 9,
|
|
||||||
parameter DAC_DATA_WID = 20,
|
|
||||||
parameter DAC_WID = 24,
|
|
||||||
parameter DAC_WAIT_BETWEEN_CMD = 10,
|
parameter DAC_WAIT_BETWEEN_CMD = 10,
|
||||||
parameter TIMER_WID = 4,
|
|
||||||
parameter STEPWID = 16,
|
|
||||||
parameter ADCNUM = 9,
|
|
||||||
parameter MAX_ADC_DATA_WID = 24,
|
|
||||||
|
|
||||||
parameter DAT_WID = 24,
|
parameter DAT_WID = 24,
|
||||||
parameter RAM_WORD = 16,
|
parameter RAM_WORD = 16,
|
||||||
parameter RAM_WID = 32,
|
parameter RAM_WID = 32,
|
||||||
|
|
||||||
parameter RAM_SIM_WAIT_TIME = 54,
|
parameter RAM_SIM_WAIT_TIME = 72,
|
||||||
parameter ADC_SIM_WAIT_TIME = 54
|
parameter ADC_SIM_WAIT_TIME = 54
|
||||||
) (
|
) (
|
||||||
input clk,
|
input clk,
|
||||||
|
output is_running,
|
||||||
|
|
||||||
input [`RASTER_CMD_WID-1:0] kernel_cmd,
|
input [`RASTER_CMD_WID-1:0] kernel_cmd,
|
||||||
input [`RASTER_DATA_WID-1:0] kernel_data_in,
|
input [`RASTER_DATA_WID-1:0] kernel_data_in,
|
||||||
|
@ -26,12 +20,12 @@ module raster_sim #(
|
||||||
input kernel_ready,
|
input kernel_ready,
|
||||||
output kernel_finished,
|
output kernel_finished,
|
||||||
|
|
||||||
output [DAC_DATA_WID-1:0] x_dac,
|
output [`DAC_DATA_WID-1:0] x_dac,
|
||||||
output [DAC_DATA_WID-1:0] y_dac,
|
output [`DAC_DATA_WID-1:0] y_dac,
|
||||||
|
|
||||||
output reg [ADCNUM-1:0] adc_arm,
|
output reg [`ADCNUM-1:0] adc_arm,
|
||||||
input [MAX_ADC_DATA_WID-1:0] adc_data [ADCNUM-1:0],
|
input [`MAX_ADC_DATA_WID-1:0] adc_data [`ADCNUM-1:0],
|
||||||
input [ADCNUM-1:0] adc_finished,
|
input [`ADCNUM-1:0] adc_finished,
|
||||||
|
|
||||||
/* DMA interface */
|
/* DMA interface */
|
||||||
output [RAM_WORD-1:0] word,
|
output [RAM_WORD-1:0] word,
|
||||||
|
@ -51,13 +45,15 @@ module raster_sim #(
|
||||||
* The code to handle each axis (X and Y) are similar.
|
* The code to handle each axis (X and Y) are similar.
|
||||||
****/
|
****/
|
||||||
|
|
||||||
reg [DAC_WID-1:0] coord_write_buf [1:0];
|
reg [`DAC_WID-1:0] coord_write_buf [1:0];
|
||||||
reg [DAC_WID-1:0] coord_to_dac [1:0];
|
/* verilator lint_off UNUSEDSIGNAL */
|
||||||
reg [DAC_WID-1:0] coord_from_dac [1:0];
|
reg [`DAC_WID-1:0] coord_to_dac [1:0];
|
||||||
|
/* verilator lint_on UNUSEDSIGNAL */
|
||||||
|
reg [`DAC_WID-1:0] coord_from_dac [1:0];
|
||||||
wire coord_arm [1:0];
|
wire coord_arm [1:0];
|
||||||
reg coord_finished [1:0];
|
reg coord_finished [1:0];
|
||||||
|
|
||||||
reg [DAC_DATA_WID-1:0] coord_dac [1:0];
|
reg [`DAC_DATA_WID-1:0] coord_dac [1:0];
|
||||||
assign x_dac = coord_dac[0];
|
assign x_dac = coord_dac[0];
|
||||||
assign y_dac = coord_dac[1];
|
assign y_dac = coord_dac[1];
|
||||||
|
|
||||||
|
@ -75,13 +71,13 @@ generate for (ci = 0; ci < 2; ci = ci + 1) begin
|
||||||
coord_to_dac[ci] <= coord_write_buf[ci];
|
coord_to_dac[ci] <= coord_write_buf[ci];
|
||||||
coord_finished[ci] <= 1;
|
coord_finished[ci] <= 1;
|
||||||
|
|
||||||
case (coord_from_dac[ci][DAC_WID-1:DAC_WID-4])
|
case (coord_from_dac[ci][`DAC_WID-1:`DAC_DATA_WID])
|
||||||
4'b1001: begin
|
4'b1001: begin
|
||||||
coord_write_buf[ci] <= {4'b1001, coord_dac[ci]};
|
coord_write_buf[ci] <= {4'b1001, coord_dac[ci]};
|
||||||
end
|
end
|
||||||
4'b0001: begin
|
4'b0001: begin
|
||||||
coord_write_buf[ci] <= 0;
|
coord_write_buf[ci] <= 0;
|
||||||
coord_dac[ci] <= coord_from_dac[ci][DAC_WID-4-1:0];
|
coord_dac[ci] <= coord_from_dac[ci][`DAC_DATA_WID-1:0];
|
||||||
end
|
end
|
||||||
default: ;
|
default: ;
|
||||||
endcase
|
endcase
|
||||||
|
@ -98,7 +94,7 @@ end endgenerate
|
||||||
* simulator so the C++ code doesn't have to implement timers manually.
|
* simulator so the C++ code doesn't have to implement timers manually.
|
||||||
****/
|
****/
|
||||||
|
|
||||||
wire [ADCNUM-1:0] adc_arm_internal;
|
wire [`ADCNUM-1:0] adc_arm_internal;
|
||||||
reg [31:0] adc_wait_cntr = 0;
|
reg [31:0] adc_wait_cntr = 0;
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
always @ (posedge clk) begin
|
||||||
|
@ -110,6 +106,7 @@ always @ (posedge clk) begin
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
adc_wait_cntr <= 0;
|
adc_wait_cntr <= 0;
|
||||||
|
adc_arm <= 0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,6 +118,7 @@ reg [31:0] ram_wait_cntr = 0;
|
||||||
always @ (posedge clk) begin
|
always @ (posedge clk) begin
|
||||||
if (!ram_write_internal) begin
|
if (!ram_write_internal) begin
|
||||||
ram_wait_cntr <= 0;
|
ram_wait_cntr <= 0;
|
||||||
|
ram_write <= 0;
|
||||||
end else if (ram_wait_cntr < RAM_SIM_WAIT_TIME) begin
|
end else if (ram_wait_cntr < RAM_SIM_WAIT_TIME) begin
|
||||||
ram_wait_cntr <= ram_wait_cntr + 1;
|
ram_wait_cntr <= ram_wait_cntr + 1;
|
||||||
end else begin
|
end else begin
|
||||||
|
@ -128,7 +126,7 @@ always @ (posedge clk) begin
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
wire [MAX_ADC_DATA_WID-1:0] ram_data;
|
wire [`MAX_ADC_DATA_WID-1:0] ram_data;
|
||||||
wire ram_commit;
|
wire ram_commit;
|
||||||
wire ram_finished;
|
wire ram_finished;
|
||||||
|
|
||||||
|
@ -155,23 +153,18 @@ ram_shim #(
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Converting array to vector, arrays are easier to handle in Verilator. */
|
/* Converting array to vector, arrays are easier to handle in Verilator. */
|
||||||
wire [ADCNUM*MAX_ADC_DATA_WID-1:0] adc_data_internal;
|
wire [`ADCNUM*`MAX_ADC_DATA_WID-1:0] adc_data_internal;
|
||||||
genvar ii;
|
genvar ii;
|
||||||
generate for (ii = 0; ii < ADCNUM; ii = ii + 1) begin
|
generate for (ii = 0; ii < `ADCNUM; ii = ii + 1) begin
|
||||||
assign adc_data_internal[(ii+1)*MAX_ADC_DATA_WID-1:ii*MAX_ADC_DATA_WID]
|
assign adc_data_internal[(ii+1)*`MAX_ADC_DATA_WID-1:ii*`MAX_ADC_DATA_WID]
|
||||||
= adc_data[ii];
|
= adc_data[ii];
|
||||||
end endgenerate
|
end endgenerate
|
||||||
|
|
||||||
raster #(
|
raster #(
|
||||||
.SAMPLEWID(SAMPLEWID),
|
.DAC_WAIT_BETWEEN_CMD(DAC_WAIT_BETWEEN_CMD)
|
||||||
.DAC_DATA_WID(DAC_DATA_WID),
|
|
||||||
.DAC_WID(DAC_WID),
|
|
||||||
.DAC_WAIT_BETWEEN_CMD(DAC_WAIT_BETWEEN_CMD),
|
|
||||||
.TIMER_WID(TIMER_WID),
|
|
||||||
.STEPWID(STEPWID),
|
|
||||||
.MAX_ADC_DATA_WID(MAX_ADC_DATA_WID)
|
|
||||||
) raster (
|
) raster (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
|
.is_running(is_running),
|
||||||
|
|
||||||
.kernel_cmd(kernel_cmd),
|
.kernel_cmd(kernel_cmd),
|
||||||
.kernel_data_in(kernel_data_in),
|
.kernel_data_in(kernel_data_in),
|
||||||
|
@ -198,5 +191,10 @@ raster #(
|
||||||
.mem_finished(ram_finished)
|
.mem_finished(ram_finished)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("raster.fst");
|
||||||
|
$dumpvars;
|
||||||
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
`undefineall
|
`undefineall
|
||||||
|
|
Loading…
Reference in New Issue