introduce control interface; pack adc_data bits into large vector instead of an array

This commit is contained in:
Peter McGoron 2022-12-21 05:16:15 +00:00
parent ac0ed9e2a7
commit a918d74f05
1 changed files with 159 additions and 137 deletions

View File

@ -5,6 +5,7 @@
* The kernel then reads these values and sends them to the controller * The kernel then reads these values and sends them to the controller
* over ethernet. * over ethernet.
*/ */
`include "raster_cmds.vh"
module raster #( module raster #(
parameter SAMPLEWID = 9, parameter SAMPLEWID = 9,
parameter DAC_DATA_WID = 20, parameter DAC_DATA_WID = 20,
@ -16,21 +17,13 @@ module raster #(
parameter MAX_ADC_DATA_WID = 24 parameter MAX_ADC_DATA_WID = 24
) ( ) (
input clk, input clk,
input arm,
output reg finished,
output reg running,
/* Amount of samples in one line (forward) */ /* Kernel interface. */
input [SAMPLEWID-1:0] max_samples_in, input [`RASTER_CMD_WID-1:0] kernel_cmd,
/* Amount of lines in the output. */ input [`RASTER_DATA_WID-1:0] kernel_data_in,
input [SAMPLEWID-1:0] max_lines_in, output reg [`RASTER_DATA_WID-1:0] kernel_data_out,
/* Wait time after each step. */ input kernel_ready,
input [TIMER_WID-1:0] settle_time_in, output reg kernel_finished,
/* Each step goes (x,y) -> (x + dx, y + dy) forward for each line of
* the output. */
input signed [DAC_DATA_WID-1:0] dx_in,
input signed [DAC_DATA_WID-1:0] dy_in,
/* X and Y DAC piezos */ /* X and Y DAC piezos */
output x_arm, output x_arm,
@ -54,9 +47,6 @@ module raster #(
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,
/* Bitmap for which ADCs are used. */
input [ADCNUM-1:0] adc_used_in,
/* 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. */
@ -114,11 +104,10 @@ localparam GET_DAC_VALUES = 1;
localparam REQUEST_DAC_VALUES = 2; localparam REQUEST_DAC_VALUES = 2;
localparam MEASURE = 3; localparam MEASURE = 3;
localparam SCAN_ADC_VALUES = 4; localparam SCAN_ADC_VALUES = 4;
localparam SEND_VALUE = 5; localparam ADVANCE_DAC_WRITE = 5;
localparam ADVANCE_DAC_WRITE = 6; localparam WAIT_ADVANCE = 6;
localparam WAIT_ADVANCE = 7; localparam NEXT_LINE = 7;
localparam NEXT_LINE = 9; localparam WAIT_ON_ARM_DEASSERT = 8;
localparam WAIT_ON_ARM_DEASSERT = 10;
localparam STATE_WID = 4; localparam STATE_WID = 4;
/********** Loop State ***********/ /********** Loop State ***********/
@ -134,26 +123,13 @@ reg signed [DAC_DATA_WID-1:0] y_val = 0;
* 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;
/* Buffer to store ADC data. The buffers are permuted in order
* for the design to read off the proper values into RAM.
*/
reg [MAX_ADC_DATA_WID-1:0] adc_data_tmp [ADCNUM-1:0];
genvar ii;
generate for (ii = 0; ii < ADCNUM - 1; ii = ii + 1) begin
always @ (posedge clk) begin
if (state == SCAN_ADC_VALUES) begin
adc_data_tmp[ii] <= adc_data_tmp[ii+1];
end else if (state == MEASURE && adc_finished == adc_arm) begin
adc_data_tmp[ii] <= adc_data[(ADCNUM-ii)*MAX_ADC_DATA_WID-1:(ADCNUM-ii-1)*MAX_ADC_DATA_WID];
end
end
end endgenerate
/********** 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 running = 0;
reg signed [DAC_DATA_WID-1:0] dx = 0; reg signed [DAC_DATA_WID-1:0] dx = 0;
reg signed [DAC_DATA_WID-1:0] dy = 0; reg signed [DAC_DATA_WID-1:0] dy = 0;
reg [TIMER_WID-1:0] settle_time = 0; reg [TIMER_WID-1:0] settle_time = 0;
@ -162,16 +138,73 @@ 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; reg [STEPWID-1:0] steps_per_sample = 0;
/********** Control Interface ************
* This code assumes that RASTER_DATA_WID is greater than all registers.
* If a register is equal to the length, omit zero extension.
*
* This uses a macro since each register is exactly the same code, just
* with different length. The arm register is special: it can be adjusted
* while the loop is running (in order to terminate the scan), but
* otherwise each register can only be modified when the loop is not
* running.
*/
// Generates code to handle read requests from the kernel.
`define generate_register_read(code, width, register) \
code: begin \
kernel_data_out[(width)-1:0] <= register; \
kernel_data_out[`RASTER_DATA_WID-1:(width)] <= 0; \
kernel_finished <= 1; \
end
// Generates code to handle write requests from the kernel.
`define generate_register(code, width, register) \
`generate_register_read(code, width, register) \
code | `RASTER_WRITE_BIT: begin \
if (!running && (code) != `RASTER_ARM) begin \
register <= kernel_data_in[(width)-1:0]; \
kernel_finished <= 1; \
end \
end
always @ (posedge clk) begin
if (!kernel_ready) kernel_finished <= 0;
else if (kernel_ready) begin case (kernel_cmd)
`generate_register(`RASTER_MAX_SAMPLES, SAMPLEWID, max_samples)
`generate_register(`RASTER_MAX_LINES, SAMPLEWID, max_lines)
`generate_register(`RASTER_SETTLE_TIME, TIMER_WID, settle_time)
`generate_register(`RASTER_DX, DAC_DATA_WID, dx)
`generate_register(`RASTER_DY, DAC_DATA_WID, dy)
`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_read(`RASTER_RUNNING, 1, running)
endcase end
end
`undef generate_register_read
`undef generate_register
task check_arm();
if (!arm) begin
state <= WAIT_ON_ARM;
running <= 0;
end
endtask
`ifdef VERILATOR
task check_deassert_dac_arm();
if (x_arm) $error("x_arm asserted");
if (y_arm) $error("y_arm asserted");
endtask
`define CHECK_DAC_ARM check_deassert_dac_arm();
`else
`define CHECK_DAC_ARM
`endif
always @ (posedge clk) begin always @ (posedge clk) begin
case (state) case (state)
WAIT_ON_ARM: begin if (arm) begin WAIT_ON_ARM: if (arm) begin
adc_used <= adc_used_in; running <= 1;
dx <= dx_in;
dy <= dy_in;
max_samples <= max_samples_in;
max_lines <= max_lines_in;
settle_time <= settle_time_in;
is_reverse <= 0; is_reverse <= 0;
sample <= 0; sample <= 0;
line <= 0; line <= 0;
@ -182,11 +215,9 @@ always @ (posedge clk) begin
y_arm <= 1; y_arm <= 1;
adc_arm <= 0; adc_arm <= 0;
end else begin state <= REQUEST_DAC_VALUES;
running <= 0; end
end end REQUEST_DAC_VALUES: if (x_finished && y_finished) begin
REQUEST_DAC_VALUES: begin
if (x_finished && y_finished) begin
x_to_dac <= 0; x_to_dac <= 0;
y_to_dac <= 0; y_to_dac <= 0;
x_arm <= 0; x_arm <= 0;
@ -194,10 +225,10 @@ always @ (posedge clk) begin
state <= GET_DAC_VALUES; state <= GET_DAC_VALUES;
counter <= 0; counter <= 0;
end end
end
GET_DAC_VALUES: if (counter < DAC_WAIT_BETWEEN_CMD) begin GET_DAC_VALUES: if (counter < DAC_WAIT_BETWEEN_CMD) begin
`CHECK_DAC_ARM
counter <= counter + 1; counter <= counter + 1;
if (!arm) state <= WAIT_ON_ARM; check_arm();
end else if (!x_arm || !y_arm) begin end else if (!x_arm || !y_arm) begin
x_arm <= 1; x_arm <= 1;
y_arm <= 1; y_arm <= 1;
@ -211,55 +242,55 @@ always @ (posedge clk) begin
state <= WAIT_ADVANCE; state <= WAIT_ADVANCE;
end end
WAIT_ADVANCE: begin WAIT_ADVANCE: if (counter < settle_time) begin
if (counter < settle_time) begin check_arm();
if (!arm) state <= WAIT_ON_ARM;
counter <= counter + 1; counter <= counter + 1;
`CHECK_DAC_ARM
end else begin end else begin
`CHECK_DAC_ARM
adc_arm <= adc_used; adc_arm <= adc_used;
adc_used_tmp <= adc_used; adc_used_tmp <= adc_used;
state <= MEASURE; state <= MEASURE;
end end
end MEASURE: if (adc_finished == adc_arm) begin
MEASURE: begin `CHECK_DAC_ARM
if (adc_finished == adc_arm) begin
adc_arm <= 0; adc_arm <= 0;
adc_data_tmp <= adc_data;
state <= SCAN_ADC_VALUES; state <= SCAN_ADC_VALUES;
counter <= 0; counter <= 0;
end end
end SCAN_ADC_VALUES: if (adc_used_tmp == 0 && !mem_commit) begin
SCAN_ADC_VALUES: begin `CHECK_DAC_ARM
if (adc_used_tmp == 0) begin
if (sample == max_samples) begin if (sample == max_samples) begin
dx <= ~dx + 1; dx <= ~dx + 1;
dy <= ~dy + 1; dy <= ~dy + 1;
is_reverse <= !is_reverse;
sample <= 0;
if (is_reverse) begin if (is_reverse) begin
state <= NEXT_LINE; state <= NEXT_LINE;
end else begin end else begin
state <= ADVANCE_DAC_WRITE; state <= ADVANCE_DAC_WRITE;
end end
is_reverse <= !is_reverse;
sample <= 0;
end else begin end else begin
state <= ADVANCE_DAC_WRITE; state <= ADVANCE_DAC_WRITE;
end end
end else if (mem_finished) begin
`CHECK_DAC_ARM
state <= SCAN_ADC_VALUES;
mem_commit <= 0;
end else begin end else begin
`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;
if (adc_used_tmp[ADCNUM-1]) begin if (adc_used_tmp[ADCNUM-1]) begin
state <= SEND_VALUE; data <= adc_data_tmp[ADCNUM*MAX_ADC_DATA_WID-1:(ADCNUM-1)*MAX_ADC_DATA_WID];
data <= adc_data_tmp[ADCNUM-1];
mem_commit <= 1; mem_commit <= 1;
end end
end end
end
SEND_VALUE: if (mem_finished) begin ADVANCE_DAC_WRITE: if (!x_arm || !y_arm) begin
if (!arm) state <= WAIT_ON_ARM;
else state <= SCAN_ADC_VALUES;
end
ADVANCE_DAC_WRITE: begin
if (!x_arm || !y_arm) begin
x_val <= x_val + dx; x_val <= x_val + dx;
y_val <= y_val + dy; y_val <= y_val + dy;
x_to_dac <= {4'b0001, x_val + dx}; x_to_dac <= {4'b0001, x_val + dx};
@ -273,13 +304,9 @@ always @ (posedge clk) begin
x_arm <= 0; x_arm <= 0;
y_arm <= 0; y_arm <= 0;
end end
end NEXT_LINE: if (!x_arm || !y_arm) begin
NEXT_LINE: begin
if (!x_arm && !y_arm) begin
if (line == max_lines) begin if (line == max_lines) begin
state <= WAIT_ON_ARM_DEASSERT; state <= WAIT_ON_ARM_DEASSERT;
finished <= 1;
running <= 0; running <= 0;
end else begin end else begin
/* rotation of (dx,dy) by 90° -> (dy, -dx) */ /* rotation of (dx,dy) by 90° -> (dy, -dx) */
@ -297,13 +324,8 @@ always @ (posedge clk) begin
x_arm <= 0; x_arm <= 0;
y_arm <= 0; y_arm <= 0;
end end
end WAIT_ON_ARM_DEASSERT: if (!arm) begin
WAIT_ON_ARM_DEASSERT: begin
if (!arm) begin
state <= WAIT_ON_ARM; state <= WAIT_ON_ARM;
finished <= 0;
end
end end
endcase endcase
end end