diff --git a/firmware/rtl/spi/spi_switch.v b/firmware/rtl/spi/spi_switch.v index 0616d94..4645293 100644 --- a/firmware/rtl/spi/spi_switch.v +++ b/firmware/rtl/spi/spi_switch.v @@ -3,20 +3,20 @@ * * This crossbar is entirely controlled by the kernel. */ -module spi_crossbar #( - parameter PORTS = 8, +module spi_switch #( + parameter PORTS = 3, ( input select[PORTS-1:0], output mosi, input miso, output sck, - output ss, + output ss_L, - input mosi_ports[PORTS-1:0], - output miso_ports[PORTS-1:0], - input sck_ports[PORTS-1:0], - input ss_ports[PORTS-1:0] + input [PORTS-1:0] mosi_ports, + output [PORTS-1:0] miso_ports, + input [PORTS-1:0] sck_ports, + input [PORTS-1:0] ss_L_ports ); /* Avoid using for loops, they might not synthesize correctly. @@ -27,23 +27,21 @@ module spi_crossbar #( mosi = mosi_ports[n]; \ miso = miso_ports[n]; \ sck = sck_ports[n]; \ - ss = ss_ports[n] + ss_L = ss_L_ports[n] `define check_select(n) \ if (select[n]) begin \ do_select(n); \ end -always @(*) begin - check_select(7) - else check_select(6) - else check_select(5) - else check_select(4) - else check_select(3) - else check_select(2) +generate if (PORTS == 2) always @(*) begin + check_select(2) else check_select(1) else do_select(0) -end +end else always @(*) begin + check_select(1) + else do_select(0) +end endgenerate endmodule `undefineall diff --git a/firmware/soc.py b/firmware/soc.py index 4cbc4ef..eab38c2 100644 --- a/firmware/soc.py +++ b/firmware/soc.py @@ -20,155 +20,246 @@ from liteeth.phy.mii import LiteEthPHYMII # IO with Subsignals make Record types, which have the name of the # subsignal as an attribute. io = [ - ("dac", 0, - Subsignal("ss", Pins("G13")), - Subsignal("mosi", Pins("B11")), - Subsignal("miso", Pins("A11")), - Subsignal("sck", Pins("D12")), - IOStandard("LVCMOS33")), - ("dac", 1, - Subsignal("ss", Pins("D13")), - Subsignal("mosi", Pins("B18")), - Subsignal("miso", Pins("A18")), - Subsignal("sck", Pins("K16")), - IOStandard("LVCMOS33")), - ("dac", 2, - Subsignal("ss", Pins("E15")), - Subsignal("mosi", Pins("E16")), - Subsignal("miso", Pins("D15")), - Subsignal("sck", Pins("C15")), - IOStandard("LVCMOS33")), - ("dac", 3, - Subsignal("ss", Pins("J17")), - Subsignal("mosi", Pins("J18")), - Subsignal("miso", Pins("K15")), - Subsignal("sck", Pins("J15")), - IOStandard("LVCMOS33")), - ("dac", 4, - Subsignal("ss", Pins("U12")), - Subsignal("mosi", Pins("V12")), - Subsignal("miso", Pins("V10")), - Subsignal("sck", Pins("V11")), - IOStandard("LVCMOS33")), - ("dac", 5, - Subsignal("ss", Pins("U14")), - Subsignal("mosi", Pins("V14")), - Subsignal("miso", Pins("T13")), - Subsignal("sck", Pins("U13")), - IOStandard("LVCMOS33")), - ("dac", 6, - Subsignal("ss", Pins("D4")), - Subsignal("mosi", Pins("D3")), - Subsignal("miso", Pins("F4")), - Subsignal("sck", Pins("F3")), - IOStandard("LVCMOS33")), - ("dac", 7, - Subsignal("ss", Pins("E2")), - Subsignal("mosi", Pins("D2")), - Subsignal("miso", Pins("H2")), - Subsignal("sck", Pins("G2")), - IOStandard("LVCMOS33")), - - ("adc", 0, - Subsignal("conv", Pins("V15")), - Subsignal("sck", Pins("U16")), - Subsignal("sdo", Pins("P14")), - IOStandard("LVCMOS33")), - ("adc", 1, - Subsignal("conv", Pins("T11")), - Subsignal("sck", Pins("R12")), - Subsignal("sdo", Pins("T14")), - IOStandard("LVCMOS33")), - ("adc", 2, - Subsignal("conv", Pins("N15")), - Subsignal("sck", Pins("M16")), - Subsignal("sdo", Pins("V17")), - IOStandard("LVCMOS33")), - ("adc", 3, - Subsignal("conv", Pins("U18")), - Subsignal("sck", Pins("R17")), - Subsignal("sdo", Pins("P17")), - IOStandard("LVCMOS33")), - ("adc", 4, - Subsignal("conv", Pins("U11")), - Subsignal("sck", Pins("V16")), - Subsignal("sdo", Pins("M13")), - IOStandard("LVCMOS33")), - ("adc", 5, - Subsignal("conv", Pins("R10")), - Subsignal("sck", Pins("R11")), - Subsignal("sdo", Pins("R13")), - IOStandard("LVCMOS33")), - ("adc", 6, - Subsignal("conv", Pins("R16")), - Subsignal("sck", Pins("N16")), - Subsignal("sdo", Pins("N14")), - IOStandard("LVCMOS33")), - ("adc", 7, - Subsignal("conv", Pins("U17")), - Subsignal("sck", Pins("T18")), - Subsignal("sdo", Pins("R18")), - IOStandard("LVCMOS33")) + ("dac_ss", 0, Pins("G13 D13 E15 J17 U12 U14 D4 E2"), IOStandard("LVCMOS33")), + ("dac_mosi", 0, Pins("B11 B18 E16 J18 V12 V14 D3 D2"), IOStandard("LVCMOS33")), + ("dac_miso", 0, Pins("A11 A18 D15 K15 V10 T13 F4 H2"), IOStandard("LVCMOS33")), + ("dac_sck", 0, Pins("D12 K16 C15 J15 V11 U13 F3 G2"), IOStandard("LVCMOS33")), + ("adc_conv", 0, Pins("V15 T11 N15 U18 U11 R10 R16 U17"), IOStandard("LVCMOS33")), + ("adc_sck", 0, Pins("U16 R12 M16 R17 V16 R11 N16 T18"), IOStandard("LVCMOS33")), + ("adc_sdo", 0, Pins("P14 T14 V17 P17 M13 R13 N14 R18"), IOStandard("LVCMOS33")) ] -class SPIMaster(Module, AutoCSR): - def __init__(self, wid, clk, pins): - self.pins = pins +class Base(Module, AutoCSR): + def __init__(self, clk, sdram): + for i in range(0,8): + setattr(self, f"dac_sel_{i}", CSRStorage(3)) + setattr(self, f"dac_finished_{i}", CSRStatus(1)) + setattr(self, f"dac_arm_{i}", CSRStorage(1)) + setattr(self, f"from_dac_{i}", CSRStatus(24)) + setattr(self, f"to_dac_{i}", CSRStorage(24)) + setattr(self, f"wf_arm_{i}", CSRStorage(1)) + setattr(self, f"wf_time_to_wait_{i}", CSRStorage(16)) + setattr(self, f"wf_refresh_start_{i}", CSRStorage(1)) + setattr(self, f"wf_refresh_finished_{i}", CSRStatus(1)) + setattr(self, f"wf_start_addr_{i}", CSRStorage(32)) + port = sdram.crossbar.get_port() + setattr(self, f"wf_sdram_{i}", LiteDRAMDMAReader(port)) - self.from_slave = CSRStatus(wid, description="Data from slave (Status)") - self.to_slave = CSRStorage(wid, description="Data to slave (Control)") - self.finished = CSRStatus(1, description="Finished transmission (Status)") - self.arm = CSRStorage(1, description="Initiate transmission (Status)") - self.ss = CSRStorage(1, description="Slave Select (active high)") + setattr(self, f"adc_finished_{i}", CSRStatus(1)) + setattr(self, f"adc_arm_{i}", CSRStorage(1)) + setattr(self, f"from_adc_{i}", CSRStatus(32)) - self.comb += self.pins.ss.eq(~self.ss.storage) + self.adc_sel_0 = CSRStorage(2) + self.cl_in_loop = CSRStatus(1) + self.cl_cmd = CSRStorage(64) + self.cl_word_in = CSRStorage(32) + self.cl_word_out = CSRStatus(32) + self.cl_start_cmd = CSRStorage(1) + self.cl_finish_cmd = CSRStatus(1) - import math + self.specials = Instance("base", + i_clk(clk), + .i_dac_miso(platform.request("dac_miso")), + .o_dac_mosi(platform.request("dac_mosi")), + .o_dac_sck(platform.request("dac_sck")), + .o_dac_ss_L(platform.request("dac_ss_L")), + .o_adc_conv(platform.request("adc_conv")), + .i_adc_sdo(platform.request("adc_sdo")), + .o_adc_sck(platform.request("adc_sck")), - self.specials += Instance("spi_master", - p_WID=wid, - p_WID_LEN=math.ceil(math.log2(wid)), - p_CYCLE_HALF_WAIT = 3, # 3 + 2 = 5, total sck = 10 cycles - p_TIMER_LEN = 3, - p_POLARITY = 0, - p_PHASE = 1, - i_clk = clk, - o_from_slave = self.from_slave.status, - i_miso = self.pins.miso, - i_to_slave = self.to_slave.storage, - o_mosi = self.pins.mosi, - o_sck_wire = self.pins.sck, - o_finished = self.finished.status, - i_arm = self.arm.storage - ) + # dac_0 + .i_dac_sel_0(self.dac_sel_0.storage), + .o_dac_finished_0(self.dac_finished_0.status), + .i_dac_arm_0(self.dac_arm_0.storage), + .o_from_dac_0(self.from_dac_0.status), + .i_to_dac_0(self.to_dac_0.storage), -class SPIMasterReadOnly(Module, AutoCSR): - def __init__(self, wid, clk, pins): - self.pins = pins + .i_wf_arm_0(self.wf_arm_0.storage), + .i_wf_time_to_wait_0(self.wf_time_to_wait_0.storage), + .i_wf_refresh_start_0(self.wf_refresh_start_0.storage), + .o_wf_refresh_finished_0(self.wf_refresh_finished_0.status), + .o_wf_start_addr_0(self.wf_start_addr_0.storage), - self.from_slave = CSRStatus(wid, description="Data from slave (Status)description=") - self.finished = CSRStatus(1, description="Finished transmission (Status)description=") - self.arm = CSRStorage(1, description="Initiate transmission (Status)description=") - self.conv = CSRStorage(1, description="Conversion (active high)description=") + .o_wf_ram_dma_addr_0(self.wf_sdram_0.sink.address), + .i_wf_ram_word_0(self.wf_sdram_0.source.data), + .o_wf_ram_read_0(self.wf_sdram_0.sink.valid), + .i_wf_ram_valid_0(self.wf_sdram_0.source.valid), - self.comb += self.pins.conv.eq(self.conv.storage) + # dac_1 + .i_dac_sel_1(self.dac_sel_1.storage), + .o_dac_finished_1(self.dac_finished_1.status), + .i_dac_arm_1(self.dac_arm_1.storage), + .o_from_dac_1(self.from_dac_1.status), + .i_to_dac_1(self.to_dac_1.storage), - import math + .i_wf_arm_1(self.wf_arm_1.storage), + .i_wf_time_to_wait_1(self.wf_time_to_wait_1.storage), + .i_wf_refresh_start_1(self.wf_refresh_start_1.storage), + .o_wf_refresh_finished_1(self.wf_refresh_finished_1.status), + .o_wf_start_addr_1(self.wf_start_addr_1.storage), - self.specials += Instance("spi_master_no_write", - p_WID=wid, - p_WID_LEN=math.ceil(math.log2(wid)), - p_CYCLE_HALF_WAIT = 1, # 1 + 2 = 3, total sck = 6 cycles - p_TIMER_LEN = 3, - p_POLARITY = 1, - p_PHASE = 0, - i_clk = clk, - o_from_slave = self.from_slave.status, - i_miso = self.pins.sdo, - o_sck_wire = self.pins.sck, - o_finished = self.finished.status, - i_arm = self.arm.storage - ) + .o_wf_ram_dma_addr_1(self.wf_sdram_1.sink.address), + .i_wf_ram_word_1(self.wf_sdram_1.source.data), + .o_wf_ram_read_1(self.wf_sdram_1.sink.valid), + .i_wf_ram_valid_1(self.wf_sdram_1.source.valid), + + # dac_2 + .i_dac_sel_2(self.dac_sel_2.storage), + .o_dac_finished_2(self.dac_finished_2.status), + .i_dac_arm_2(self.dac_arm_2.storage), + .o_from_dac_2(self.from_dac_2.status), + .i_to_dac_2(self.to_dac_2.storage), + + .i_wf_arm_2(self.wf_arm_2.storage), + .i_wf_time_to_wait_2(self.wf_time_to_wait_2.storage), + .i_wf_refresh_start_2(self.wf_refresh_start_2.storage), + .o_wf_refresh_finished_2(self.wf_refresh_finished_2.status), + .o_wf_start_addr_2(self.wf_start_addr_2.storage), + + .o_wf_ram_dma_addr_2(self.wf_sdram_2.sink.address), + .i_wf_ram_word_2(self.wf_sdram_2.source.data), + .o_wf_ram_read_2(self.wf_sdram_2.sink.valid), + .i_wf_ram_valid_2(self.wf_sdram_2.source.valid), + + # dac_3 + .i_dac_sel_3(self.dac_sel_3.storage), + .o_dac_finished_3(self.dac_finished_3.status), + .i_dac_arm_3(self.dac_arm_3.storage), + .o_from_dac_3(self.from_dac_3.status), + .i_to_dac_3(self.to_dac_3.storage), + + .i_wf_arm_3(self.wf_arm_3.storage), + .i_wf_time_to_wait_3(self.wf_time_to_wait_3.storage), + .i_wf_refresh_start_3(self.wf_refresh_start_3.storage), + .o_wf_refresh_finished_3(self.wf_refresh_finished_3.status), + .o_wf_start_addr_3(self.wf_start_addr_3.storage), + + .o_wf_ram_dma_addr_3(self.wf_sdram_3.sink.address), + .i_wf_ram_word_3(self.wf_sdram_3.source.data), + .o_wf_ram_read_3(self.wf_sdram_3.sink.valid), + .i_wf_ram_valid_3(self.wf_sdram_3.source.valid), + + # dac_4 + .i_dac_sel_4(self.dac_sel_4.storage), + .o_dac_finished_4(self.dac_finished_4.status), + .i_dac_arm_4(self.dac_arm_4.storage), + .o_from_dac_4(self.from_dac_4.status), + .i_to_dac_4(self.to_dac_4.storage), + + .i_wf_arm_4(self.wf_arm_4.storage), + .i_wf_time_to_wait_4(self.wf_time_to_wait_4.storage), + .i_wf_refresh_start_4(self.wf_refresh_start_4.storage), + .o_wf_refresh_finished_4(self.wf_refresh_finished_4.status), + .o_wf_start_addr_4(self.wf_start_addr_4.storage), + + .o_wf_ram_dma_addr_4(self.wf_sdram_4.sink.address), + .i_wf_ram_word_4(self.wf_sdram_4.source.data), + .o_wf_ram_read_4(self.wf_sdram_4.sink.valid), + .i_wf_ram_valid_4(self.wf_sdram_4.source.valid), + + # dac_5 + .i_dac_sel_5(self.dac_sel_5.storage), + .o_dac_finished_5(self.dac_finished_5.status), + .i_dac_arm_5(self.dac_arm_5.storage), + .o_from_dac_5(self.from_dac_5.status), + .i_to_dac_5(self.to_dac_5.storage), + + .i_wf_arm_5(self.wf_arm_5.storage), + .i_wf_time_to_wait_5(self.wf_time_to_wait_5.storage), + .i_wf_refresh_start_5(self.wf_refresh_start_5.storage), + .o_wf_refresh_finished_5(self.wf_refresh_finished_5.status), + .o_wf_start_addr_5(self.wf_start_addr_5.storage), + + .o_wf_ram_dma_addr_5(self.wf_sdram_5.sink.address), + .i_wf_ram_word_5(self.wf_sdram_5.source.data), + .o_wf_ram_read_5(self.wf_sdram_5.sink.valid), + .i_wf_ram_valid_5(self.wf_sdram_5.source.valid), + + # dac_6 + .i_dac_sel_6(self.dac_sel_6.storage), + .o_dac_finished_6(self.dac_finished_6.status), + .i_dac_arm_6(self.dac_arm_6.storage), + .o_from_dac_6(self.from_dac_6.status), + .i_to_dac_6(self.to_dac_6.storage), + + .i_wf_arm_6(self.wf_arm_6.storage), + .i_wf_time_to_wait_6(self.wf_time_to_wait_6.storage), + .i_wf_refresh_start_6(self.wf_refresh_start_6.storage), + .o_wf_refresh_finished_6(self.wf_refresh_finished_6.status), + .o_wf_start_addr_6(self.wf_start_addr_6.storage), + + .o_wf_ram_dma_addr_6(self.wf_sdram_6.sink.address), + .i_wf_ram_word_6(self.wf_sdram_6.source.data), + .o_wf_ram_read_6(self.wf_sdram_6.sink.valid), + .i_wf_ram_valid_6(self.wf_sdram_6.source.valid), + + # dac_7 + .i_dac_sel_7(self.dac_sel_7.storage), + .o_dac_finished_7(self.dac_finished_7.status), + .i_dac_arm_7(self.dac_arm_7.storage), + .o_from_dac_7(self.from_dac_7.status), + .i_to_dac_7(self.to_dac_7.storage), + + .i_wf_arm_7(self.wf_arm_7.storage), + .i_wf_time_to_wait_7(self.wf_time_to_wait_7.storage), + .i_wf_refresh_start_7(self.wf_refresh_start_7.storage), + .o_wf_refresh_finished_7(self.wf_refresh_finished_7.status), + .o_wf_start_addr_7(self.wf_start_addr_7.storage), + + .o_wf_ram_dma_addr_7(self.wf_sdram_7.sink.address), + .i_wf_ram_word_7(self.wf_sdram_7.source.data), + .o_wf_ram_read_7(self.wf_sdram_7.sink.valid), + .i_wf_ram_valid_7(self.wf_sdram_7.source.valid), + + .i_adc_sel_0(self.adc_sel_0.storage), + + # adc_0 + .o_adc_finished_0(self.adc_finished_0.status), + .i_adc_arm_0(self.adc_arm_0.storage), + .o_from_adc_0(self.from_adc_0.status), + + # adc_1 + .o_adc_finished_1(self.adc_finished_1.status), + .i_adc_arm_1(self.adc_arm_1.storage), + .o_from_adc_1(self.from_adc_1.status), + + # adc_2 + .o_adc_finished_2(self.adc_finished_2.status), + .i_adc_arm_2(self.adc_arm_2.storage), + .o_from_adc_2(self.from_adc_2.status), + + # adc_3 + .o_adc_finished_3(self.adc_finished_3.status), + .i_adc_arm_3(self.adc_arm_3.storage), + .o_from_adc_3(self.from_adc_3.status), + + # adc_4 + .o_adc_finished_4(self.adc_finished_4.status), + .i_adc_arm_4(self.adc_arm_4.storage), + .o_from_adc_4(self.from_adc_4.status), + + # adc_5 + .o_adc_finished_5(self.adc_finished_5.status), + .i_adc_arm_5(self.adc_arm_5.storage), + .o_from_adc_5(self.from_adc_5.status), + + # adc_6 + .o_adc_finished_6(self.adc_finished_6.status), + .i_adc_arm_6(self.adc_arm_6.storage), + .o_from_adc_6(self.from_adc_6.status), + + # adc_7 + .o_adc_finished_7(self.adc_finished_7.status), + .i_adc_arm_7(self.adc_arm_7.storage), + .o_from_adc_7(self.from_adc_7.status), + + .o_cl_in_loop(self.cl_in_loop.status), + .i_cl_cmd(self.cl_cmd.storage), + .i_cl_word_in(self.cl_word_in.storage), + .o_cl_word_out(self.cl_word_out.status), + .i_cl_start_cmd(self.cl_start_cmd.storage), + .o_cl_finish_cmd(self.cl_finish_cmd.status) + ) # Clock and Reset Generator class _CRG(Module): @@ -207,8 +298,16 @@ class CryoSNOM1SoC(SoCCore): sys_clk_freq = int(100e6) platform = board_spec.Platform(variant=variant, toolchain="symbiflow") self.submodules.crg = _CRG(platform, sys_clk_freq, True) - platform.add_source("rtl/spi/spi_master.v") - platform.add_source("rtl/spi/spi_master_no_write.v") + platform.add_source("rtl/spi/spi_master_ss.v") + platform.add_source("rtl/spi/spi_master_ss_no_write.v") + platform.add_source("rtl/control_loop/sign_extend.v") + platform.add_source("rtl/control_loop/intsat.v") + platform.add_source("rtl/control_loop/boothmul.v") + platform.add_source("rtl/control_loop/control_loop_math.v") + platform.add_source("rtl/control_loop/control_loop.v") + platform.add_source("rtl/control_loop/spi_switch.v") + platform.add_source("rtl/waveform/waveform.v") + platform.add_source("rtl/spi/base/base.v") # SoCCore does not have sane defaults (no integrated rom) SoCCore.__init__(self, @@ -229,10 +328,14 @@ class CryoSNOM1SoC(SoCCore): csr_ordering="big", timer_uptime = True) + # This initializes the connection to the physical DRAM interface. self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"), memtype = "DDR3", nphases = 4, sys_clk_freq = sys_clk_freq) + # Synchronous dynamic ram. This is what controls all access to RAM. + # This houses the "crossbar", which negotiates all RAM accesses to different + # modules, including the verilog interfaces (waveforms etc.) self.add_sdram("sdram", phy = self.ddrphy, module = MT41K128M16(sys_clk_freq, "1:4"), @@ -246,9 +349,7 @@ class CryoSNOM1SoC(SoCCore): # Add the DAC and ADC pins as GPIO. They will be used directly # by Zephyr. platform.add_extension(io) - for i in range(0,8): - setattr(self.submodules, f"dac{i}", SPIMaster(24, ClockSignal(), platform.request("dac", i))) - setattr(self.submodules, f"adc{i}", SPIMasterReadOnly(24, ClockSignal(), platform.request("adc", i))) + self.submodules.sdram = Base(ClockSignal(), self.sdram) def main(): soc = CryoSNOM1SoC("a7-35")