diff --git a/milkymist/m1crg/__init__.py b/milkymist/m1crg/__init__.py index 0d20fd8f9..6938e98df 100644 --- a/milkymist/m1crg/__init__.py +++ b/milkymist/m1crg/__init__.py @@ -3,8 +3,9 @@ from fractions import Fraction from migen.fhdl.structure import * from migen.fhdl.specials import Instance from migen.fhdl.module import Module +from migen.bank.description import * -class M1CRG(Module): +class M1CRG(Module, AutoReg): def __init__(self, pads, outfreq1x): self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys2x_270 = ClockDomain() @@ -17,12 +18,22 @@ class M1CRG(Module): self.clk4x_wr_strb = Signal() self.clk4x_rd_strb = Signal() + self._r_cmd_data = RegisterField(10) + self._r_send_cmd_data = RegisterRaw() + self._r_send_go = RegisterRaw() + self._r_status = RegisterField(3, READ_ONLY, WRITE_ONLY) + ### infreq = 50*1000000 ratio = Fraction(outfreq1x)/Fraction(infreq) in_period = float(Fraction(1000000000)/Fraction(infreq)) + vga_progdata = Signal() + vga_progen = Signal() + vga_progdone = Signal() + vga_locked = Signal() + self.specials += Instance("m1crg", Instance.Parameter("in_period", in_period), Instance.Parameter("f_mult", ratio.numerator), @@ -48,4 +59,40 @@ class M1CRG(Module): Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p), Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n), Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk), - Instance.Output("vga_clk_pad", pads.vga_clk)) + Instance.Output("vga_clk_pad", pads.vga_clk), + + Instance.Input("vga_progclk", ClockSignal()), + Instance.Input("vga_progdata", vga_progdata), + Instance.Input("vga_progen", vga_progen), + Instance.Output("vga_progdone", vga_progdone), + Instance.Output("vga_locked", vga_locked)) + + remaining_bits = Signal(max=11) + transmitting = Signal() + self.comb += transmitting.eq(remaining_bits != 0) + sr = Signal(10) + self.sync += [ + If(self._r_send_cmd_data.re, + remaining_bits.eq(10), + sr.eq(self._r_cmd_data.field.r) + ).Elif(transmitting, + remaining_bits.eq(remaining_bits - 1), + sr.eq(sr[1:]) + ) + ] + self.comb += [ + vga_progdata.eq(transmitting & sr[0]), + vga_progen.eq(transmitting | self._r_send_go.re) + ] + + # enforce gap between commands + busy_counter = Signal(max=14) + busy = Signal() + self.comb += busy.eq(busy_counter != 0) + self.sync += If(self._r_send_cmd_data.re, + busy_counter.eq(13) + ).Elif(busy, + busy_counter.eq(busy_counter - 1) + ) + + self.comb += self._r_status.field.w.eq(Cat(busy, vga_progdone, vga_locked)) diff --git a/software/include/hw/flags.h b/software/include/hw/flags.h index 64f6a7edb..759246a69 100644 --- a/software/include/hw/flags.h +++ b/software/include/hw/flags.h @@ -18,4 +18,8 @@ #define MINIMAC_EV_RX1 0x2 #define MINIMAC_EV_TX 0x4 +#define CLKGEN_STATUS_BUSY 0x1 +#define CLKGEN_STATUS_PROGDONE 0x2 +#define CLKGEN_STATUS_LOCKED 0x4 + #endif /* __HW_FLAGS_H */ diff --git a/top.py b/top.py index 96d1787b6..e5b111783 100644 --- a/top.py +++ b/top.py @@ -65,17 +65,18 @@ class M1ClockPads: class SoC(Module): csr_base = 0xe0000000 csr_map = { - "uart": 0, - "dfii": 1, - "identifier": 2, - "timer0": 3, - "minimac": 4, - "fb": 5, - "asmiprobe": 6, - "dvisampler0": 7, - "dvisampler0_edid_mem": 8, - "dvisampler1": 9, - "dvisampler1_edid_mem": 10, + "crg": 0, + "uart": 1, + "dfii": 2, + "identifier": 3, + "timer0": 4, + "minimac": 5, + "fb": 6, + "asmiprobe": 7, + "dvisampler0": 8, + "dvisampler0_edid_mem": 9, + "dvisampler1": 10, + "dvisampler1_edid_mem": 11, } interrupt_map = { @@ -134,6 +135,7 @@ class SoC(Module): # # CSR # + self.submodules.crg = m1crg.M1CRG(M1ClockPads(platform), clk_freq) self.submodules.uart = uart.UART(platform.request("serial"), clk_freq, baud=115200) self.submodules.identifier = identifier.Identifier(0x4D31, version, int(clk_freq)) self.submodules.timer0 = timer.Timer() @@ -151,11 +153,10 @@ class SoC(Module): # for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)): self.comb += self.cpu.interrupt[v].eq(getattr(self, k).ev.irq) - + # # Clocking # - self.submodules.crg = m1crg.M1CRG(M1ClockPads(platform), clk_freq) self.comb += [ self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb) diff --git a/verilog/m1crg/m1crg.v b/verilog/m1crg/m1crg.v index d5582d405..bf91d2be9 100644 --- a/verilog/m1crg/m1crg.v +++ b/verilog/m1crg/m1crg.v @@ -33,7 +33,14 @@ module m1crg #( /* VGA clock */ output vga_clk, /* < buffered, to internal clock network */ - output vga_clk_pad /* < forwarded through ODDR2, to I/O */ + output vga_clk_pad, /* < forwarded through ODDR2, to I/O */ + + /* VGA clock control */ + input vga_progclk, + input vga_progdata, + input vga_progen, + output vga_progdone, + output vga_locked ); /* @@ -257,7 +264,6 @@ assign eth_tx_clk = eth_tx_clk_pad; * VGA clock */ -// TODO: hook up the reprogramming interface DCM_CLKGEN #( .CLKFXDV_DIVIDE(2), .CLKFX_DIVIDE(4), @@ -270,15 +276,15 @@ DCM_CLKGEN #( .CLKFX(vga_clk), .CLKFX180(), .CLKFXDV(), - .LOCKED(), - .PROGDONE(), .STATUS(), .CLKIN(pllout4), .FREEZEDCM(1'b0), - .PROGCLK(1'b0), - .PROGDATA(), - .PROGEN(1'b0), - .RST(1'b0) + .PROGCLK(vga_progclk), + .PROGDATA(vga_progdata), + .PROGEN(vga_progen), + .PROGDONE(vga_progdone), + .LOCKED(vga_locked), + .RST(~pll_lckd) ); ODDR2 #(