upsilon/gateware/rtl/base/base.v.m4

397 lines
11 KiB
Plaintext
Raw Normal View History

2023-03-13 21:40:17 -04:00
m4_changequote(`⟨', `⟩')
m4_changecom(⟨/*⟩, ⟨*/⟩)
2023-03-15 17:08:55 -04:00
m4_define(generate_macro, ⟨m4_define(M4_$1, $2)⟩)
2023-06-15 12:24:35 -04:00
/*
2023-06-21 17:04:54 -04:00
Copyright 2023 (C) Peter McGoron
2023-04-04 15:10:32 -04:00
2023-06-21 17:04:54 -04:00
This file is a part of Upsilon, a free and open source software project.
For license terms, refer to the files in `doc/copying` in the Upsilon
source distribution.
_____________________________________________________________________
This is the module that collects all Verilog and exports a single interface
that is connected to the CPU by LiteX.
In this future, this module should be written into soc.py
Since yosys only allows for standard Verilog (no system verilog),
arrays (which would make everything much cleaner) cannot be used.
A preprocessor is used instead, and M4 is used because it is much
cleaner than the Verilog preprocessor (which is bad).
TODO: individual RST pins
*/
2023-04-04 15:10:32 -04:00
2023-03-13 21:40:17 -04:00
/*********************************************************/
/********************** M4 macros ************************/
/*********************************************************/
2023-04-04 15:10:32 -04:00
/* This macro is used in the module declaration.
* The first argument is the number of wires the select switch must
* support (2 for most DACs, 3 for the control loop DAC).
* The second argument is the DAC number.
*/
2023-03-13 21:40:17 -04:00
m4_define(m4_dac_wires, ⟨
input [$1-1:0] dac_sel_$2,
output dac_finished_$2,
input dac_arm_$2,
2023-06-23 14:51:35 -04:00
output [DAC_WID-1:0] dac_recv_buf_$2,
input [DAC_WID-1:0] dac_send_buf_$2
2023-03-13 21:40:17 -04:00
2023-06-02 18:10:35 -04:00
/*
2023-03-13 21:40:17 -04:00
input wf_arm_$2,
2023-03-15 02:29:19 -04:00
input wf_halt_on_finish_$2,
output wf_finished_$2,
2023-03-14 00:06:42 -04:00
input [WF_TIMER_WID-1:0] wf_time_to_wait_$2,
2023-03-13 21:40:17 -04:00
input wf_refresh_start_$2,
2023-03-14 00:06:42 -04:00
input [WF_RAM_WID-1:0] wf_start_addr_$2,
2023-03-13 21:40:17 -04:00
output wf_refresh_finished_$2,
2023-04-02 17:35:51 -04:00
output wf_running_$2,
2023-03-13 21:40:17 -04:00
2023-03-14 00:06:42 -04:00
output [WF_RAM_WID-1:0] wf_ram_dma_addr_$2,
input [WF_RAM_WORD_WID-1:0] wf_ram_word_$2,
2023-03-13 21:40:17 -04:00
output wf_ram_read_$2,
input wf_ram_valid_$2
2023-06-02 18:10:35 -04:00
*/
2023-03-13 21:40:17 -04:00
⟩)
2023-04-04 15:10:32 -04:00
/* Same thing but for ADCs */
2023-03-13 21:40:17 -04:00
m4_define(m4_adc_wires, ⟨
2023-05-10 14:35:57 -04:00
input [$3-1:0] adc_sel_$2,
2023-03-13 21:40:17 -04:00
output adc_finished_$2,
input adc_arm_$2,
2023-06-23 14:51:35 -04:00
output [$1-1:0] adc_recv_buf_$2
2023-03-13 21:40:17 -04:00
⟩)
2023-04-04 15:10:32 -04:00
/* This is used in the body of the module. It declares the interconnect
* for each DAC. The first argument is the amount of switch ports the
* DAC requires (2 for most DACs, 3 for the control loop DAC). The
* second argument is the DAC number.
*/
2023-03-13 21:40:17 -04:00
m4_define(m4_dac_switch, ⟨
wire [$1-1:0] mosi_port_$2;
wire [$1-1:0] miso_port_$2;
wire [$1-1:0] sck_port_$2;
wire [$1-1:0] ss_L_port_$2;
spi_switch #(
2023-03-14 00:06:42 -04:00
.PORTS($1)
2023-03-13 21:40:17 -04:00
) switch_$2 (
.select(dac_sel_$2),
2023-03-14 00:06:42 -04:00
.mosi(dac_mosi[$2]),
.miso(dac_miso[$2]),
.sck(dac_sck[$2]),
.ss_L(dac_ss_L[$2]),
2023-03-13 21:40:17 -04:00
.mosi_ports(mosi_port_$2),
.miso_ports(miso_port_$2),
.sck_ports(sck_port_$2),
2023-03-14 00:06:42 -04:00
.ss_L_ports(ss_L_port_$2)
2023-03-13 21:40:17 -04:00
);
spi_master_ss #(
.WID(DAC_WID),
.WID_LEN(DAC_WID_SIZ),
.CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT),
.TIMER_LEN(DAC_CYCLE_HALF_WAIT_SIZ),
.POLARITY(DAC_POLARITY),
.PHASE(DAC_PHASE),
.SS_WAIT(DAC_SS_WAIT),
.SS_WAIT_TIMER_LEN(DAC_SS_WAIT_SIZ)
) dac_master_$2 (
.clk(clk),
2023-05-10 14:35:57 -04:00
.rst_L(rst_L),
2023-03-13 21:40:17 -04:00
.mosi(mosi_port_$2[0]),
.miso(miso_port_$2[0]),
.sck_wire(sck_port_$2[0]),
2023-03-14 00:06:42 -04:00
.ss_L(ss_L_port_$2[0]),
2023-03-13 21:40:17 -04:00
.finished(dac_finished_$2),
.arm(dac_arm_$2),
2023-06-23 14:51:35 -04:00
.from_slave(dac_recv_buf_$2),
.to_slave(dac_send_buf_$2)
2023-06-02 18:10:35 -04:00
)
2023-03-13 21:40:17 -04:00
2023-06-02 18:10:35 -04:00
/*
2023-03-13 21:40:17 -04:00
waveform #(
.DAC_WID(DAC_WID),
.DAC_WID_SIZ(DAC_WID_SIZ),
.DAC_POLARITY(DAC_POLARITY),
.DAC_PHASE(DAC_PHASE),
.DAC_CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT),
.DAC_CYCLE_HALF_WAIT_SIZ(DAC_CYCLE_HALF_WAIT_SIZ),
.DAC_SS_WAIT(DAC_SS_WAIT),
.DAC_SS_WAIT_SIZ(DAC_SS_WAIT_SIZ),
.TIMER_WID(WF_TIMER_WID),
.WORD_WID(WF_WORD_WID),
.WORD_AMNT_WID(WF_WORD_AMNT_WID),
.WORD_AMNT(WF_WORD_AMNT),
.RAM_WID(WF_RAM_WID),
.RAM_WORD_WID(WF_RAM_WORD_WID),
.RAM_WORD_INCR(WF_RAM_WORD_INCR)
) waveform_$2 (
.clk(clk),
.arm(wf_arm_$2),
2023-03-15 02:29:19 -04:00
.halt_on_finish(wf_halt_on_finish_$2),
2023-04-02 17:35:51 -04:00
.running(wf_running_$2),
2023-03-15 02:29:19 -04:00
.finished(wf_finished_$2),
2023-03-13 21:40:17 -04:00
.time_to_wait(wf_time_to_wait_$2),
.refresh_start(wf_refresh_start_$2),
.start_addr(wf_start_addr_$2),
.refresh_finished(wf_refresh_finished_$2),
2023-03-14 00:06:42 -04:00
.ram_dma_addr(wf_ram_dma_addr_$2),
2023-03-13 21:40:17 -04:00
.ram_word(wf_ram_word_$2),
.ram_read(wf_ram_read_$2),
.ram_valid(wf_ram_valid_$2),
.mosi(mosi_port_$2[1]),
.sck(sck_port_$2[1]),
2023-03-14 00:06:42 -04:00
.ss_L(ss_L_port_$2[1])
2023-03-13 21:40:17 -04:00
)
2023-06-02 18:10:35 -04:00
*/
2023-03-13 21:40:17 -04:00
⟩)
2023-04-04 15:10:32 -04:00
/* Same thing but for ADCs */
2023-03-13 21:40:17 -04:00
m4_define(m4_adc_switch, ⟨
2023-05-10 14:35:57 -04:00
wire adc_mosi_unused_output_$2;
wire [$3-1:0] adc_mosi_port_$2; /* Unused! */
wire [$3-1:0] adc_sdo_port_$2;
wire [$3-1:0] adc_sck_port_$2;
wire [$3-1:0] adc_conv_L_port_$2;
spi_switch #(
.PORTS($3)
) adc_switch_$2 (
.select(adc_sel_$2),
.mosi(adc_mosi_unused_output_$2),
.miso(adc_sdo[$2]),
.sck(adc_sck[$2]),
.ss_L(adc_conv_L[$2]),
.mosi_ports(adc_mosi_port_$2),
.miso_ports(adc_sdo_port_$2),
.sck_ports(adc_sck_port_$2),
.ss_L_ports(adc_conv_L_port_$2)
);
2023-03-14 00:06:42 -04:00
spi_master_ss_no_write #(
2023-03-13 21:40:17 -04:00
.WID($1),
.WID_LEN(ADC_WID_SIZ),
.CYCLE_HALF_WAIT(ADC_CYCLE_HALF_WAIT),
2023-03-14 00:06:42 -04:00
.TIMER_LEN(ADC_CYCLE_HALF_WAIT_SIZ),
2023-03-13 21:40:17 -04:00
.SS_WAIT(ADC_CONV_WAIT),
.SS_WAIT_TIMER_LEN(ADC_CONV_WAIT_SIZ),
.POLARITY(ADC_POLARITY),
.PHASE(ADC_PHASE)
) adc_master_$2 (
.clk(clk),
2023-05-10 14:35:57 -04:00
.rst_L(rst_L),
.miso(adc_sdo_port_$2[0]),
.sck_wire(adc_sck_port_$2[0]),
.ss_L(adc_conv_L_port_$2[0]),
2023-03-13 21:40:17 -04:00
.finished(adc_finished_$2),
.arm(adc_arm_$2),
2023-06-23 14:51:35 -04:00
.from_slave(adc_recv_buf_$2)
2023-05-10 14:35:57 -04:00
);
/* 2nd option for each ADC is the non-converting option.
* This is used to flush output from reset ADCs.
2023-05-11 11:43:30 -04:00
* TODO: Lower power consumption by having SCK low while converter is
* not running? May require change to spi code.
2023-05-10 14:35:57 -04:00
*/
assign adc_sdo_port[1] = adc_sdo_port[0];
assign adc_sck_port[1] = adc_sck_port[0];
assign adc_conv_L_port[1] = 1;
2023-03-13 21:40:17 -04:00
⟩)
/*********************************************************/
/*********************** Verilog *************************/
/*********************************************************/
module base #(
2023-06-02 18:10:35 -04:00
parameter DAC_PORTS = 1,
m4_define(DAC_PORTS_CONTROL_LOOP, (DAC_PORTS + 1))
2023-03-13 21:40:17 -04:00
2023-06-21 17:04:54 -04:00
parameter DAC_NUM = 8, // Number of DACs
parameter DAC_WID = 24, // Bit width of DAC command
parameter DAC_DATA_WID = 20, // Bit with of DAC register
parameter DAC_WID_SIZ = 5, // number of bits required to store DAC_DATA_WID
parameter DAC_POLARITY = 0, // DAC SCK polarity
parameter DAC_PHASE = 1, // DAC SCK phase
2023-03-13 21:40:17 -04:00
parameter DAC_CYCLE_HALF_WAIT = 10,
parameter DAC_CYCLE_HALF_WAIT_SIZ = 4,
parameter DAC_SS_WAIT = 5,
parameter DAC_SS_WAIT_SIZ = 3,
parameter WF_TIMER_WID = 32,
2023-03-14 00:06:42 -04:00
parameter WF_WORD_WID = 20,
2023-03-13 21:40:17 -04:00
parameter WF_WORD_AMNT_WID = 11,
2023-03-14 00:06:42 -04:00
parameter [WF_WORD_AMNT_WID-1:0] WF_WORD_AMNT = 2047,
2023-03-13 21:40:17 -04:00
parameter WF_RAM_WID = 32,
parameter WF_RAM_WORD_WID = 16,
parameter WF_RAM_WORD_INCR = 2,
2023-05-10 14:35:57 -04:00
parameter ADC_PORTS = 2,
m4_define(ADC_PORTS_CONTROL_LOOP, (ADC_PORTS + 1))
2023-03-13 21:40:17 -04:00
parameter ADC_NUM = 8,
/* Three types of ADC. For now assume that their electronics
* are similar enough, just need different numbers for the width.
*/
parameter ADC_TYPE1_WID = 18,
parameter ADC_TYPE2_WID = 16,
parameter ADC_TYPE3_WID = 24,
parameter ADC_WID_SIZ = 5,
2023-06-21 17:04:54 -04:00
parameter ADC_CYCLE_HALF_WAIT = 5,
parameter ADC_CYCLE_HALF_WAIT_SIZ = 3,
2023-03-13 21:40:17 -04:00
parameter ADC_POLARITY = 1,
parameter ADC_PHASE = 0,
/* The ADC takes maximum 527 ns to capture a value.
* The clock ticks at 10 ns. Change for different clocks!
*/
2023-06-21 17:04:54 -04:00
parameter ADC_CONV_WAIT = 60,
2023-03-13 21:40:17 -04:00
parameter ADC_CONV_WAIT_SIZ = 6,
parameter CL_CONSTS_WHOLE = 21,
parameter CL_CONSTS_FRAC = 43,
parameter CL_CONSTS_SIZ = 7,
parameter CL_DELAY_WID = 16,
m4_define(CL_CONSTS_WID, (CL_CONSTS_WHOLE + CL_CONSTS_FRAC))
m4_define(CL_DATA_WID, CL_CONSTS_WID)
2023-03-13 21:40:17 -04:00
parameter CL_READ_DAC_DELAY = 5,
parameter CL_CYCLE_COUNT_WID = 18
) (
input clk,
2023-05-10 14:35:57 -04:00
input rst_L,
output [11-1:0] set_low,
2023-03-13 21:40:17 -04:00
output [DAC_NUM-1:0] dac_mosi,
input [DAC_NUM-1:0] dac_miso,
output [DAC_NUM-1:0] dac_sck,
output [DAC_NUM-1:0] dac_ss_L,
output [ADC_NUM-1:0] adc_conv,
input [ADC_NUM-1:0] adc_sdo,
output [ADC_NUM-1:0] adc_sck,
m4_dac_wires(DAC_PORTS_CONTROL_LOOP, 0),
2023-03-13 21:40:17 -04:00
m4_dac_wires(DAC_PORTS, 1),
m4_dac_wires(DAC_PORTS, 2),
m4_dac_wires(DAC_PORTS, 3),
m4_dac_wires(DAC_PORTS, 4),
m4_dac_wires(DAC_PORTS, 5),
m4_dac_wires(DAC_PORTS, 6),
m4_dac_wires(DAC_PORTS, 7),
2023-05-10 14:35:57 -04:00
m4_adc_wires(ADC_TYPE1_WID, 0, ADC_PORTS_CONTROL_LOOP),
m4_adc_wires(ADC_TYPE1_WID, 1, ADC_PORTS),
m4_adc_wires(ADC_TYPE1_WID, 2, ADC_PORTS),
2023-06-08 21:37:24 -04:00
m4_adc_wires(ADC_TYPE2_WID, 3, ADC_PORTS),
m4_adc_wires(ADC_TYPE2_WID, 4, ADC_PORTS),
m4_adc_wires(ADC_TYPE2_WID, 5, ADC_PORTS),
m4_adc_wires(ADC_TYPE3_WID, 6, ADC_PORTS),
m4_adc_wires(ADC_TYPE3_WID, 7, ADC_PORTS),
2023-03-13 21:40:17 -04:00
2023-06-28 17:38:41 -04:00
input cl_assert_change,
output cl_change_made,
2023-06-28 18:49:26 -04:00
output cl_in_loop,
2023-04-20 15:20:42 -04:00
2023-06-28 17:38:41 -04:00
input cl_run_loop_in,
input [ADC_TYPE1_WID-1:0] cl_setpt_in,
input [CL_DATA_WID-1:0] cl_P_in,
input [CL_DATA_WID-1:0] cl_I_in,
input [CL_DELAY_WID-1:0] cl_delay_in,
2023-06-28 18:49:26 -04:00
output [CL_CYCLE_COUNT_WID-1:0] cl_cycle_count,
2023-06-28 17:38:41 -04:00
output [DAC_DATA_WID-1:0] cl_z_pos,
2023-06-28 18:49:26 -04:00
output [ADC_TYPE1_WID-1:0] cl_z_measured
2023-03-13 21:40:17 -04:00
);
assign set_low = 0;
2023-03-13 21:40:17 -04:00
wire [ADC_NUM-1:0] adc_conv_L;
2023-03-14 00:06:42 -04:00
assign adc_conv = ~adc_conv_L;
2023-03-13 21:40:17 -04:00
m4_dac_switch(DAC_PORTS_CONTROL_LOOP, 0);
2023-03-13 21:40:17 -04:00
m4_dac_switch(DAC_PORTS, 1);
m4_dac_switch(DAC_PORTS, 2);
m4_dac_switch(DAC_PORTS, 3);
m4_dac_switch(DAC_PORTS, 4);
m4_dac_switch(DAC_PORTS, 5);
m4_dac_switch(DAC_PORTS, 6);
m4_dac_switch(DAC_PORTS, 7);
2023-06-20 13:14:26 -04:00
`define MAKE_TEST_CLOCK
2023-05-11 15:31:52 -04:00
`ifdef MAKE_TEST_CLOCK
2023-06-20 13:14:26 -04:00
reg [8-1:0] counter = 0;
2023-05-10 14:35:57 -04:00
always @ (posedge clk) begin
if (!rst_L) begin
counter <= 0;
test_clock <= 0;
end else begin
2023-06-20 13:14:26 -04:00
if (counter == ADC_CYCLE_HALF_WAIT) begin
2023-05-10 14:35:57 -04:00
counter <= 0;
test_clock <= !test_clock;
end else begin
counter <= counter + 1;
end
end
end
2023-05-11 15:31:52 -04:00
`endif
2023-04-20 15:20:42 -04:00
2023-05-10 14:35:57 -04:00
m4_adc_switch(ADC_TYPE1_WID, 0, ADC_PORTS_CONTROL_LOOP);
m4_adc_switch(ADC_TYPE1_WID, 1, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 2, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 3, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 4, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 5, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 6, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 7, ADC_PORTS);
2023-03-13 21:40:17 -04:00
control_loop #(
.ADC_WID(ADC_TYPE1_WID),
.ADC_WID_SIZ(ADC_WID_SIZ),
.ADC_CYCLE_HALF_WAIT(ADC_CYCLE_HALF_WAIT),
.ADC_CYCLE_HALF_WAIT_SIZ(ADC_CYCLE_HALF_WAIT_SIZ),
.ADC_POLARITY(ADC_POLARITY),
.ADC_PHASE(ADC_PHASE),
.ADC_CONV_WAIT(ADC_CONV_WAIT),
.ADC_CONV_WAIT_SIZ(ADC_CONV_WAIT_SIZ),
.CONSTS_WHOLE(CL_CONSTS_WHOLE),
.CONSTS_FRAC(CL_CONSTS_FRAC),
.CONSTS_SIZ(CL_CONSTS_SIZ),
.DELAY_WID(CL_DELAY_WID),
.READ_DAC_DELAY(CL_READ_DAC_DELAY),
.CYCLE_COUNT_WID(CL_CYCLE_COUNT_WID),
.DAC_WID(DAC_WID),
.DAC_WID_SIZ(DAC_WID_SIZ),
.DAC_DATA_WID(DAC_DATA_WID),
.DAC_POLARITY(DAC_POLARITY),
.DAC_PHASE(DAC_PHASE),
.DAC_CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT),
.DAC_CYCLE_HALF_WAIT_SIZ(DAC_CYCLE_HALF_WAIT_SIZ),
.DAC_SS_WAIT(DAC_SS_WAIT),
.DAC_SS_WAIT_SIZ(DAC_SS_WAIT_SIZ)
) cl (
.clk(clk),
2023-05-10 14:35:57 -04:00
.rst_L(rst_L),
2023-03-13 21:40:17 -04:00
.in_loop(cl_in_loop),
2023-06-02 18:10:35 -04:00
.dac_mosi(mosi_port_0[1]),
.dac_miso(miso_port_0[1]),
.dac_ss_L(ss_L_port_0[1]),
.dac_sck(sck_port_0[1]),
2023-05-10 14:35:57 -04:00
.adc_miso(adc_sdo_port_0[2]),
.adc_conv_L(adc_conv_L_port_0[2]),
.adc_sck(adc_sck_port_0[2]),
2023-06-28 17:38:41 -04:00
.assert_change(cl_assert_change),
.change_made(cl_change_made),
.run_loop_in(cl_run_loop_in),
.setpt_in(cl_setpt_in),
.P_in(cl_P_in),
.I_in(cl_I_in),
.delay_in(cl_delay_in),
.cycle_count(cl_cycle_count),
.z_pos(cl_z_pos),
.z_measured(cl_z_measured)
2023-03-13 21:40:17 -04:00
);
endmodule