buppu3 / tnCart

FPGA cartridge for MSX
BSD 3-Clause "New" or "Revised" License
29 stars 6 forks source link

Clock unstable during boot, tnCart stuck into boot loop #14

Open herraa1 opened 2 months ago

herraa1 commented 2 months ago

After reports of many users that latest tnCartWonder bitstreams were not booting into their MSXs when using WonderTANG! V2.0b boards (and strangely my Panasonic FS-A1WSX and Toshiba HX-10 were not affected, or at least rarely), I started troubleshooting the issue.

Users observed that their WonderTANG! V2.0b boards got stuck while booting, showing a continuous fast-blinking board led, and not progressing to the MSX boot screen (video was black).

I made a minimal tnCart configuration for my WonderTANG! V2.0b with the bare minimum to make it wondertang-compatible, i.e.:

User pakoto from msx.org (thanks!) help me making tests remotely with his WonderTANG! V2.0b and his Panasonic FS-A1 (and a Sanyo MSX1) which he was reporting were failing 100% of the time. Using that bare minimum setup we observed indeed the same boot loop with the fast-blinking board led.

I started suspecting that something was going on during the boot process, before freeing the MSX to boot.

I changed a bit the setup so that I could use the LED output for debugging some signals, connecting it to a logic analyzer. I diagnosed the CLK_MEM_READY signal through the LED pin (IO 75) and saw that during all those failed boots, the CLK_MEM_READY was deasserted before the bootloader had time to complete, causing a RESET and provoking the boot loop.

I thought what change could have caused that problem, and remembered that in commit 62a343aea63ec7127754807950ec2bd71299bfeb "Fix #7 Synchronize the operating clock with the bus clock" you switched the clock for deriving the base clock for the fpga from the 27MHz clock of the Tang Nano 20k to the 3.58MHz of the cartridge clock.

To confirm if that was the issue, and without further analyzing the root cause of the clock not being stable for the whole bootloader phase, I did a quick test switching the base clock to the old 108MHz derived from the 27MHz Tang Nano 20k (just the CLK_MEM, without touching anything else for a quick test).

So basically commenting out this:

/*
    wire CLK_MEM_LOCK;
    assign CLK_MEM_READY = RESET_n && CLK_MEM_LOCK;
    rPLL u_pll_base (
        .CLKOUT(CLK_MEM),
        .LOCK(CLK_MEM_LOCK),
        .CLKOUTP(CLK_MEM_P),
        .CLKOUTD(),
        .CLKOUTD3(),
        .RESET(!RESET_n),
        .RESET_P(1'b0),
        .CLKIN(CLK_IN),
        .CLKFB(1'b0),
        .FBDSEL({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
        .IDSEL({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
        .ODSEL({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
        .PSDA({1'b0,1'b0,1'b0,1'b0}),
        .DUTYDA({1'b0,1'b0,1'b0,1'b0}),
        .FDLY({1'b1,1'b1,1'b1,1'b1})
    );

    defparam u_pll_base.FCLKIN = "3.58";
    defparam u_pll_base.DYN_IDIV_SEL = "false";
    defparam u_pll_base.IDIV_SEL = 0;
    defparam u_pll_base.DYN_FBDIV_SEL = "false";
    defparam u_pll_base.FBDIV_SEL = 29;
    defparam u_pll_base.DYN_ODIV_SEL = "false";
    defparam u_pll_base.ODIV_SEL = 8;
    defparam u_pll_base.PSDA_SEL = "1000";
    defparam u_pll_base.DYN_DA_EN = "false";
    defparam u_pll_base.DUTYDA_SEL = "1000";
    defparam u_pll_base.CLKOUT_FT_DIR = 1'b1;
    defparam u_pll_base.CLKOUTP_FT_DIR = 1'b1;
    defparam u_pll_base.CLKOUT_DLY_STEP = 0;
    defparam u_pll_base.CLKOUTP_DLY_STEP = 0;
    defparam u_pll_base.CLKFB_SEL = "internal";
    defparam u_pll_base.CLKOUT_BYPASS = "false";
    defparam u_pll_base.CLKOUTP_BYPASS = "false";
    defparam u_pll_base.CLKOUTD_BYPASS = "false";
    defparam u_pll_base.DYN_SDIV_SEL = 2;
    defparam u_pll_base.CLKOUTD_SRC = "CLKOUT";
    defparam u_pll_base.CLKOUTD3_SRC = "CLKOUT";
    defparam u_pll_base.DEVICE = "GW2AR-18C";
*/

and adding this:

    wire CLK_MEM_LOCK;
    assign CLK_MEM_READY = RESET_n && CLK_MEM_LOCK;
    localparam FREQ=108_000;
    rPLL u_pll_base (
        .CLKOUT(CLK_MEM),
        .LOCK(CLK_MEM_LOCK),
        .CLKOUTP(CLK_MEM_P),
        .CLKOUTD(),
        .CLKOUTD3(),
        .RESET(!RESET_n),
        .RESET_P(1'b0),
        .CLKIN(CLK_27M),
        .CLKFB(1'b0),
        .FBDSEL(6'b000000),
        .IDSEL(6'b000000),
        .ODSEL(6'b000000),
        .PSDA(4'b0000),
        .DUTYDA(4'b0000),
        .FDLY(4'b1111)
    );
    defparam u_pll_base.FCLKIN = "27";
    defparam u_pll_base.DYN_IDIV_SEL = "false";
    defparam u_pll_base.IDIV_SEL = 0;
    defparam u_pll_base.DYN_FBDIV_SEL = "false";
    defparam u_pll_base.FBDIV_SEL = 3;
    defparam u_pll_base.DYN_ODIV_SEL = "false";
    defparam u_pll_base.ODIV_SEL = 8;
    defparam u_pll_base.PSDA_SEL = "1000";
    defparam u_pll_base.DYN_DA_EN = "false";
    defparam u_pll_base.DUTYDA_SEL = "1000";
    defparam u_pll_base.CLKOUT_FT_DIR = 1'b1;
    defparam u_pll_base.CLKOUTP_FT_DIR = 1'b1;
    defparam u_pll_base.CLKOUT_DLY_STEP = 0;
    defparam u_pll_base.CLKOUTP_DLY_STEP = 0;
    defparam u_pll_base.CLKFB_SEL = "internal";
    defparam u_pll_base.CLKOUT_BYPASS = "false";
    defparam u_pll_base.CLKOUTP_BYPASS = "false";
    defparam u_pll_base.CLKOUTD_BYPASS = "false";
    defparam u_pll_base.DYN_SDIV_SEL = 2;
    defparam u_pll_base.CLKOUTD_SRC = "CLKOUT";
    defparam u_pll_base.CLKOUTD3_SRC = "CLKOUT";
    defparam u_pll_base.DEVICE = "GW2AR-18C";

After that change, the WonderTANG! V2.0 of user pakoto started to boot 100% reliably in his Panasonic FS-A1 and Sanyo MSX1 without getting into the boot loop anymore (something that never happened before).

So, there is clearly a problem when using the CART_CLK, as at least in some MSX, the clock is not stable (and becomes not ready) in the middle of the bootloader process.

As I said, I didn't further analyze the root cause of it, but maybe it could be related to the following: as the CART_CLK comes from the CPU clock and the CPU clock comes from the VDP clock, maybe the fact that SYSRESET is help during bootloader causes the VDP to stop providing a clock. On some MSX that happens before than others, letting some of them complete the bootloader (and get to boot the MSX system) and others to get stuck into the dreaded boot loop. And that explains too why when using the 27MHz clock to derive the base clock, the bootlopp never happens.

Of course, changing the clock that way was just to confirm the issue, and it is NOT a proposed solution as that change has other implications, and you made that change to fix other issues.

So something needs to be thought to fix the problem the right way.

Looking forward for your comments.

buppu3 commented 2 months ago

Thanks for investigating this issue.

You have identified the following issues

What causes the clock signal to be unstable?

You mentioned that the VDP clock may be stopped, but why is it repeating? Will the power supply voltage fluctuate due to changes in load, causing unstable oscillation?

About the problem when using with onboard 27MHz

Dot clock is generated in sync with 3.58MHz, causing jitter in the DVI output of the V9990 emulation, resulting in DVI devices that cannot be supported

If the SYNC_CLK_EN parameter of the UMA module is set to 0, the module will operate asynchronously and the DIV output will be stable. However, I do not know how 4MB RAM, Nextor, and FM-BIOS will work under these conditions.

Countermeasure

I think there are two means.

buppu3 commented 2 months ago

I quickly checked. If I generate the base clock at 27MHz and set SYNC_CLK_EN to 0, I can start up on FS-A1F, but 1chip MSX hangs up while starting NEXTOR.

herraa1 commented 2 months ago

You mentioned that the VDP clock may be stopped, but why is it repeating? Will the power supply voltage fluctuate due to changes in load, causing unstable oscillation?

That was a simply a wild guess with no actual check.

Either the clock is stopping (and restarting, otherwise the bootloader would not loop) or the clock is glitching enough for the pll to loose sync. I don't think the power supply is specifically involved, as there were reports from very different machines (with linear and switched power supplies).

I took a quick look at the manual for V9958 (which is the VDP present on my Omega and Panasonic A1-WSX) to check what should be the behavior of CPUCLK when the V9958 chip RESET_n signal is low, but couldn't find any information (SYS_RESET_n is kept low until the BOOTLOADER completes).

Maybe the CPUCLK is not guaranteed to work flawlessly until RESET_n is high. This should be further investigated.

Thanks.

buppu3 commented 2 months ago

Eventually, once the reset on the MSX side is released and the clock is stable, the PLL should remain locked. But why is the output clock forever unstable?

Due to the specifications of the cartridge bus, it is not possible to send a reset signal from the cartridge side to the MSX. So the SYS_RESET_n signal is used internally by the FPGA and does not affect the reset on the MSX side. (The reason why the screen remains black is due to the WAIT signal, not the RESET signal)

herraa1 commented 2 months ago

Oh, you are completely right. I forgot for a moment that the cartridge reset signal is an input signal from the tnCart point of view... So the cpu clock from the vdp should be running continuously.

Then I wonder if those clock glitches do happen too outside of the bootloader phase (and if not why only on the bootloader phase).

In the bootloader phase they cause a direct reset of the bootloader. But outside the bootloader phase (when BOOT_n is 1) they should also cause a reset of the SDRAM module (via CLK_MEM_READY which depends on the pll lock) and most of the modules (via RESET_n which depends on CLK_BASE_READY which depends on the pll lock).

Isn't it?

buppu3 commented 2 months ago

Does the cartridge reboot when the boot loader is running or when it completes? If this issue occurs after the bootloader completes, the following possibilities exist:

Accessing SDRAM in the FPGA from MSX generates a lot of noise. Isn't it possible that that noise gets mixed into the clock signal and causes the PLL to unlock? Once the tnCart bootloader is complete, the MSX BIOS will begin searching for RAM. This creates a lot of noise on the power line. (I checked the 5V pin on the tnCart board with an oscilloscope. However, I don't know if there is a similar phenomenon with the WonderTANG board.)

If this is the cause, it cannot be fixed within the FPGA, so the only option is to use the 27MHz onboard clock.

NewFile1

herraa1 commented 2 months ago

I made the following test.

I modified the fpga code to use again the 3.58MHz clock but this time considering the BASE clock ready when at least the PLL has locked once.

    /***************************************************************
     * 3.58MHz * 30 = 107.4MHz
     ***************************************************************/
    wire CLK_MEM_LOCK;
    logic CLK_MEM_LOCK_ONCE = 1'b0;
    always_ff @(posedge CLK_MEM_LOCK) begin
        CLK_MEM_LOCK_ONCE = 1'b1;
    end
    assign CLK_MEM_READY = RESET_n && CLK_MEM_LOCK_ONCE;
    rPLL u_pll_base (
        .CLKOUT(CLK_MEM),
        .LOCK(CLK_MEM_LOCK),
        .CLKOUTP(CLK_MEM_P),
        .CLKOUTD(),
        .CLKOUTD3(),
        .RESET(!RESET_n),
        .RESET_P(1'b0),
        .CLKIN(CLK_IN),
        .CLKFB(1'b0),
        .FBDSEL({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
        .IDSEL({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
        .ODSEL({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
        .PSDA({1'b0,1'b0,1'b0,1'b0}),
        .DUTYDA({1'b0,1'b0,1'b0,1'b0}),
        .FDLY({1'b1,1'b1,1'b1,1'b1})
    );

    defparam u_pll_base.FCLKIN = "3.58";
    defparam u_pll_base.DYN_IDIV_SEL = "false";
    defparam u_pll_base.IDIV_SEL = 0;
    defparam u_pll_base.DYN_FBDIV_SEL = "false";
    defparam u_pll_base.FBDIV_SEL = 29;
    defparam u_pll_base.DYN_ODIV_SEL = "false";
    defparam u_pll_base.ODIV_SEL = 8;
    defparam u_pll_base.PSDA_SEL = "1000";
    defparam u_pll_base.DYN_DA_EN = "false";
    defparam u_pll_base.DUTYDA_SEL = "1000";
    defparam u_pll_base.CLKOUT_FT_DIR = 1'b1;
    defparam u_pll_base.CLKOUTP_FT_DIR = 1'b1;
    defparam u_pll_base.CLKOUT_DLY_STEP = 0;
    defparam u_pll_base.CLKOUTP_DLY_STEP = 0;
    defparam u_pll_base.CLKFB_SEL = "internal";
    defparam u_pll_base.CLKOUT_BYPASS = "false";
    defparam u_pll_base.CLKOUTP_BYPASS = "false";
    defparam u_pll_base.CLKOUTD_BYPASS = "false";
    defparam u_pll_base.DYN_SDIV_SEL = 2;
    defparam u_pll_base.CLKOUTD_SRC = "CLKOUT";
    defparam u_pll_base.CLKOUTD3_SRC = "CLKOUT";
    defparam u_pll_base.DEVICE = "GW2AR-18C";

I also used the board LED to signal if the bootloader has started or ended, and once ended, if it was executed again. The LED ignores anything related to LedBoot or LedNextor, and lights only according to LedDebug. It should briefly turn on when the MSX powers on, then off when the bootloader finishes, and remain on again in case the bootloader is restarted at least once.

    BOOTLOADER #(
        .XFER_SRC_ADDR  (CONFIG::FLASH_ADDR_BIOS),
        .XFER_DST_ADDR  (CONFIG::RAM_ADDR_BIOS),
        .XFER_SIZE      (CONFIG::FLASH_SIZE_BIOS),
        .MEGAROM_CLEAR_ADDR(CONFIG::RAM_ADDR_MEGAROM),
        .MEGAROM_CLEAR_SIZE(32768),
        .RAM_CLEAR_ADDR (CONFIG::RAM_ADDR_RAM),
        .RAM_CLEAR_SIZE (65536)
    ) u_boot (
        .RESET_n,
        .CLK,
        .Flash,
        .Ram            (ExpRam[RAM_BOOTLOADER]),
        .Led            (LedBoot),
        .ClearMegarom   (1'b1),
        .READY          (BOOT_n)
    );

    logic [1:0] state = 0;
    always_ff @(posedge CLK) begin
        case(state)
            default: begin
                LedDebug.State <= LedDebug.LED_STATE_ON;
                if (BOOT_n) state <= 2'd1;
            end
            2'd1: begin
                LedDebug.State <= LedDebug.LED_STATE_OFF;
                if (!BOOT_n) state <= 2'd2;
            end
            2'd2: begin
                LedDebug.State <= LedDebug.LED_STATE_ON;
            end
        endcase
    end

I did many tests and that's what I found (remember with the 3.58MHz clock as reference):

So, answering your question, according to my tests, the PLL unlocks randomly only during the bootloader phase.

So it seems that we can't reliably use the 3.58MHz clock during the bootloader phase, but for some reason, it works fine after that and we can use it then.

buppu3 commented 2 months ago

u_boot.RESET_n is the same as RESET_n in the TOP module, and is generated in the section below. When CLK_BASE_READY and sdram_ready both become 1, RESET_n also becomes 1.

        reg reset_n = 0;
        assign RESET_n = reset_n;
        always_ff @(posedge CLK_BASE or negedge CLK_BASE_READY or negedge sdram_ready) begin
            if(!CLK_BASE_READY) reset_n <= 0;       // PLL 準備中ならリセット
            else if(!sdram_ready) reset_n <= 0;     // SDRAM 準備中ならリセット
            else reset_n <= 1; 
        end

The READY signal generation for the SDRAM module is as follows: READY will not become 0 unless RESET_n (same as CLK_BASE_READY) becomes 0. Considering that, wouldn't sdram_ready also remain at 1 after going from 0 to 1?

    always_ff @(posedge CLK or negedge RESET_n)
    begin
        if(!RESET_n)                 READY <= 0;
        else if(state == STATE_IDLE) READY <= 1;
    end

Is something happening somewhere other than what is described in the source? Are the SETUP time and HOLD time of registers such as READY signal and RESET signal within the specified range?

herraa1 commented 2 months ago

The Timing Analysis Report is clean (no red lines), but the report assumes the clock is working correctly. So maybe due to the clock instability those SETUP and HOLD times are not completely met in the real world.

buppu3 commented 2 months ago

I changed tnCartWonder to use 3.58Mhz(defined XXX_TEMP_FIX_MUST_BE_FIXED_IN_A_PROPER_WAY_WONT_PASS_TIMING_REPORT_AND_MAY_CAUSE_INSTABILITIES) and looked at the post-synthesis list and found that BOOT_n was dependent on the state of the LED module.

It seems that tnCart 3.58MHz and tnCartWonder 27MHz give correct synthesis results. It is unclear why this result occurs.

tnCartWonder3.58Mhz synthesis result

LUT3 n199_s3 (  // wire n199_7 = blink_cout[2:0] == 3'b111;
    .F(n199_7),
    .I0(blink_count[0]),
    .I1(blink_count[1]),
    .I2(blink_count[2]) 
);
defparam n199_s3.INIT=8'h80;

LUT4 n198_s3 (  // wire n198_7 = blink_count[3:0] == 4'b1111;
    .F(n198_7),
    .I0(blink_count[0]),
    .I1(blink_count[1]),
    .I2(blink_count[2]),
    .I3(blink_count[3]) 
);
defparam n198_s3.INIT=16'h8000;

LUT4 n202_s7 (  // wire n202_11 = blink_count[22:19] == 4'b1111;
    .F(n202_11),
    .I0(blink_count[19]),
    .I1(blink_count[21]),
    .I2(blink_count[20]),
    .I3(blink_count[22]) 
);
defparam n202_s7.INIT=16'h1000;

LUT4 n202_s8 (  // wire n202_12 = blink_count[14:13] == 2'b11 & blink_count[18] & blink_count[16];
    .F(n202_12),
    .I0(blink_count[16]),
    .I1(blink_count[18]),
    .I2(blink_count[13]),
    .I3(blink_count[14]) 
);
defparam n202_s8.INIT=16'h1000;

LUT4 n202_s9 (  // wire n202_13 = blink_count[10] & !blink_count[12] & !blink_count[11] & !blink_count[9];
    .F(n202_13),
    .I0(blink_count[9]),
    .I1(blink_count[11]),
    .I2(blink_count[12]),
    .I3(blink_count[10]) 
);
defparam n202_s9.INIT=16'h0100;

LUT3 n196_s3 (  // wire n196_7 = blink[5:4] == 2'b11 & n198_7;
    .F(n196_7),
    .I0(blink_count[4]),
    .I1(blink_count[5]),
    .I2(n198_7) 
);
defparam n196_s3.INIT=8'h80;

LUT4 n202_s5 (  // wire n202_9 = {blink_count[17], n202_11, blink_count[15], blink_count[6]} == 4'b1100;
    .F(n202_9),
    .I0(blink_count[6]),
    .I1(blink_count[15]),
    .I2(n202_11),
    .I3(blink_count[17]) 
);
defparam n202_s5.INIT=16'h1000;

LUT4 n202_s6 (  // wire n202_10 = n202_13 & blink_count[8] & blink_count[7] & n202_12;
    .F(n202_10),
    .I0(n202_12),
    .I1(blink_count[7]),
    .I2(blink_count[8]),
    .I3(n202_13) 
);
defparam n202_s6.INIT=16'h8000;

LUT4 n202_s4 (  // 
    .F(n202_8),
    .I0(n196_7),
    .I1(n202_9),
    .I2(n202_10),
    .I3(\LedBoot.State [0]) 
);
defparam n202_s4.INIT=16'h7F00;

LUT3 n199_s2 (  // wire n199_6 = n202_8 & (n199_7 ^ blink_count[3]);
    .F(n199_6),
    .I0(n199_7),
    .I1(blink_count[3]),
    .I2(n202_8) 
);
defparam n199_s2.INIT=8'h60;

DFFCE READY_s0 (    // always_ff @(posedge CLK_BASE or negedge n119_6) if(n119_6) BOOT_n <= 0; else if(CE) BOOT_n <= VCC;
    .Q(BOOT_n),
    .D(VCC),
    .CLK(CLK_BASE),
    .CE(n189_10),
    .CLEAR(n119_6) 
);

tnCartWonder27Mhz synthesis result

rPLL u_pll_base (
    .CLKOUT(CLK_BASE),
    .CLKOUTP(O_sdram_clk_d),
    .CLKOUTD(u_pll_base_3_CLKOUTD),
    .CLKOUTD3(u_pll_base_3_CLKOUTD3),
    .LOCK(CLK_MEM_LOCK),
    .CLKIN(CLK_27M_d),
    .CLKFB(GND),
    .FBDSEL({GND,GND,GND,GND,GND,GND}),
    .IDSEL({GND,GND,GND,GND,GND,GND}),
    .ODSEL({GND,GND,GND,GND,GND,GND}),
    .DUTYDA({GND,GND,GND,GND}),
    .PSDA({GND,GND,GND,GND}),
    .FDLY({VCC,VCC,VCC,VCC}),
    .RESET(GND),
    .RESET_P(GND) 
);

INV n12_s2 (
    .O(n12_6),
    .I(CLK_MEM_LOCK) 
);

LUT4 \Ram.TIMING_s  (   // \Ram.TIMING = state[2:0] == 8;
    .F(\Ram.TIMING ),
    .I0(state[0]),
    .I1(state[1]),
    .I2(state[2]),
    .I3(\Ram.TIMING_3 ) 
);
defparam \Ram.TIMING_s .INIT=16'h0100;

DFFCE READY_s0 (
    .Q(sdram_ready),
    .D(VCC),
    .CLK(CLK_BASE),
    .CE(\Ram.TIMING ),
    .CLEAR(n12_6) 
);

LUT2 n35_s0 (   // n35_4 = sdram_ready & CLK_MEM_LOCK;
    .F(n35_4),
    .I0(sdram_ready),
    .I1(CLK_MEM_LOCK) 
);
defparam n35_s0.INIT=4'h7;

DFFC reset_n_s0 (
    .Q(DAC_SDMODE_n_d),
    .D(VCC),
    .CLK(CLK_BASE),
    .CLEAR(n35_4) 
);

INV n119_s2 (
    .O(n119_6),
    .I(DAC_SDMODE_n_d) 
);

DFFCE READ_s0 (
    .Q(BOOT_n),
    .D(VCC),
    .CLK(CLK_BASE),
    .CE(n189_10),
    .CLEAR(n119_6)
);

tnCart3.58Mhz synthesis result

rPLL u_pll_base (
    .CLKOUT(CLK_BASE),
    .CLKOUTP(O_sdram_clk_d),
    .CLKOUTD(u_pll_base_3_CLKOUTD),
    .CLKOUTD3(u_pll_base_3_CLKOUTD3),
    .LOCK(CLK_MEM_LOCK),
    .CLKIN(CART_CLOCK_d),
    .CLKFB(GND),
    .FBDSEL({GND,GND,GND,GND,GND,GND}),
    .IDSEL({GND,GND,GND,GND,GND,GND}),
    .ODSEL({GND,GND,GND,GND,GND,GND}),
    .DUTYDA({GND,GND,GND,GND}),
    .PSDA({GND,GND,GND,GND}),
    .FDLY({VCC,VCC,VCC,VCC}),
    .RESET(GND),
    .RESET_P(GND) 
);

INV n12_s2 (
    .O(n12_6),
    .I(CLK_MEM_LOCK) 
);

DFFCE READY_s0 (
    .Q(sdram_ready),
    .D(VCC),
    .CLK(CLK_BASE),
    .CE(\Ram.TIMING ),
    .CLEAR(n12_6) 
);

LUT2 n34_s0 (
    .F(n34_4),
    .I0(sdram_ready),
    .I1(CLK_MEM_LOCK) 
);

DFFC reset_n_s0 (
    .Q(reset_n),
    .D(VCC),
    .CLK(CLK_BASE),
    .CLEAR(n34_4) 
);

INV n414_s2 (
    .O(n414_6),
    .I(reset_n) 
);

DFFCE READY_s0 (
    .Q(BOOT_n),
    .D(VCC),
    .CLK(CLK_BASE),
    .CE(n189_10),
    .CLEAR(n414_6) 
);
buppu3 commented 2 months ago

I think it's a bug in the gowin synthesizer.

DAC_SDMODE_n may be the cause, so I fixed it as follows. This resulted in a synthesis result independent of the LED module.

I'm not sure if this is the cause of the bootloop, so please check.

    assign DAC_SDMODE_n = RESET_n;

    reg ff_dac_rst;
    assign DAC_SDMODE_n = ff_dac_rst;
    always_ff @(posedge CLK_DAC) ff_dac_rst <= RESET_n;
herraa1 commented 2 months ago

I just tested the proposed fix, but the boot loop continues.

diff --git a/rtl/src/board/wondertang_rev200b/wondertang_board_rev200b_clock.sv b/rtl/src/board/wondertang_rev200b/wondertang_board_rev200b_clock.sv
index 72b457c..2612fbe 100644
--- a/rtl/src/board/wondertang_rev200b/wondertang_board_rev200b_clock.sv
+++ b/rtl/src/board/wondertang_rev200b/wondertang_board_rev200b_clock.sv
@@ -121,7 +121,7 @@ module WONDERTANG_BOARD_REV200B_CLOCK (
     defparam u_div_tmds.DIV_MODE = "5";
     defparam u_div_tmds.GSREN = "false";

-`ifdef XXX_TEMP_FIX_MUST_BE_FIXED_IN_A_PROPER_WAY_WONT_PASS_TIMING_REPORT_AND_MAY_CAUSE_INSTABILITIES
+`ifndef XXX_TEMP_FIX_MUST_BE_FIXED_IN_A_PROPER_WAY_WONT_PASS_TIMING_REPORT_AND_MAY_CAUSE_INSTABILITIES
     /***************************************************************
      * 3.58MHz * 30 = 107.4MHz
      ***************************************************************/
diff --git a/rtl/src/wondertang_board_rev200b_top.sv b/rtl/src/wondertang_board_rev200b_top.sv
index a94969d..a85d3d9 100644
--- a/rtl/src/wondertang_board_rev200b_top.sv
+++ b/rtl/src/wondertang_board_rev200b_top.sv
@@ -434,7 +434,10 @@ module WONDERTANG_BOARD_REV200B_TOP (
     SOUND_IF SoundInternal();

     // unmute the DAC
-    assign DAC_SDMODE_n = RESET_n;
+//    assign DAC_SDMODE_n = RESET_n;
+    reg ff_dac_rst;
+    assign DAC_SDMODE_n = ff_dac_rst;
+    always_ff @(posedge CLK_DAC) ff_dac_rst <= RESET_n;

     /***************************************************************
      * VIDEO

I reverted the define to go back to the 27MHz clock but leaving new DAC_SDMODE_n non-combinatorial assignment, and the boot loop goes away as on the original temp fix:

diff --git a/rtl/src/wondertang_board_rev200b_top.sv b/rtl/src/wondertang_board_rev200b_top.sv
index a94969d..a85d3d9 100644
--- a/rtl/src/wondertang_board_rev200b_top.sv
+++ b/rtl/src/wondertang_board_rev200b_top.sv
@@ -434,7 +434,10 @@ module WONDERTANG_BOARD_REV200B_TOP (
     SOUND_IF SoundInternal();

     // unmute the DAC
-    assign DAC_SDMODE_n = RESET_n;
+//    assign DAC_SDMODE_n = RESET_n;
+    reg ff_dac_rst;
+    assign DAC_SDMODE_n = ff_dac_rst;
+    always_ff @(posedge CLK_DAC) ff_dac_rst <= RESET_n;

     /***************************************************************
      * VIDEO
herraa1 commented 2 months ago

By the way, I just verified that the bootloop problem is not specific of the WonderTANG! V2.0b board, but it is also present in WonderTANG! V1.02d and WonderTANG! V1.01c boards.

And in WonderTANG! V1.02d the only difference is the swap of MSEL0 and MSEL1.

I think that the fact that DAC_SDMODE_n appears in the 27MHz tnCartWoder synthesis is just because it is combinatorially assigned to RESET_n, and then the synthesis tool may have replaced RESET_n by DAC_SDMODE_n with the same outcome.

The strange thing is the synthesis output you posted on the 3.58MHz tnCartWonder, where the RESET_n has been replaced by some expression depending on the blink count of the LED...

herraa1 commented 2 months ago

I just did another test. I commented out the current LED code (so that the synthesis tool can't generate that weird output you showed), and replaced it with code to just turn on the LED when the TF Card is accessed (i.e. when LedNextor turns it on).

But the bootloop is still there when using the 3.58MHz clock (and gets fixed as soon as switching to the 27MHz clock).

diff --git a/rtl/src/peripheral/led.sv b/rtl/src/peripheral/led.sv
index 7f22f77..ea9f140 100644
--- a/rtl/src/peripheral/led.sv
+++ b/rtl/src/peripheral/led.sv
@@ -73,6 +73,7 @@ module LED #(
     output  reg     LedPort             // LED ポート
 );

+`ifdef COMMENT_OUT
     /***************************************************************
      * ディレイカウンタ
      ***************************************************************/
@@ -125,6 +126,10 @@ module LED #(
             LedPort <= (delay_count != 0) ? 1'b1 : 1'b0;
         end
     end
+`else
+    always_ff @(posedge CLK)
+        LedPort <= (LedNextor.State == LedNextor.LED_STATE_ON);
+`endif

 endmodule
buppu3 commented 2 months ago

When I checked again, I couldn't get any results that depended on the LED module, so I think it was a misunderstanding.

buppu3 commented 2 months ago

Since this problem cannot be resolved immediately, onboard 27 MHz will be used until the cause is identified. Continue to investigate the cause of the problem, as it is not a root cause resolution.

buppu3 commented 2 months ago

I have observed a noise in the 3.58 MHz clock and a reboot of the boot loader. However, I do not know if this is the cause of the repeat. CLOCK

buppu3 commented 1 month ago

The CART_CLOCK noise was reproducible and occurred immediately after the V9990 video output started. However, it no longer occurs after cleaning the card edge terminals. Did the buffer IC become unstable due to fluctuations in current consumption?

herraa1 commented 1 month ago

The CART_CLOCK noise was reproducible and occurred immediately after the V9990 video output started. However, it no longer occurs after cleaning the card edge terminals. Did the buffer IC become unstable due to fluctuations in current consumption?

Note that in my original tests, the V9990 was not even enabled (to simplify things and reduce rtl build times for tests).

Do you have reproduced the boot loop on your tnCart (not WonderTANG!) boards?

xKNIGHTMAREx commented 3 weeks ago

I have tested the tncart on PCB 2.0 on a Philips VG8020 and it gets stuck when starting nextor.sys and a led on the tang lights up. Is there a solution? Thanks.

herraa1 commented 3 weeks ago

I have tested the tncart on PCB 2.0 on a Philips VG8020 and it gets stuck when starting nextor.sys and a led on the tang lights up. Is there a solution? Thanks.

That description seems to be unrelated to this specific issue. It should be better that you open a specific issue for the WonderTANG using the tnCart rtl on a Philips VG8020. Also note that WonderTANG 2.0 is currently not supported by the tnCart github project (it is "supported" in tnCartWonder though), so you should first make sure that any issue with WonderTANG 2.0 can be reproduced also with WonderTANG 1.01c or 1.02d to get support here.

buppu3 commented 3 weeks ago

The CART_CLOCK noise was reproducible and occurred immediately after the V9990 video output started. However, it no longer occurs after cleaning the card edge terminals. Did the buffer IC become unstable due to fluctuations in current consumption?

Note that in my original tests, the V9990 was not even enabled (to simplify things and reduce rtl build times for tests).

Do you have reproduced the boot loop on your tnCart (not WonderTANG!) boards?

The tnCart board has not had a bootloop problem yet so far.

herraa1 commented 3 weeks ago

Do you have reproduced the boot loop on your tnCart (not WonderTANG!) boards?

The tnCart board has not had a bootloop problem yet so far.

Great. Do you think that rev2 is ready to be built? Or it still requires some updates/fixes? I would build a tnCart board to compare with WonderTANG! if it is considered ok to get built in its current status. Do you plan to publish the complete rev2 kicad design files, besides the schematic?

Thanks!

buppu3 commented 3 weeks ago

Great. Do you think that rev2 is ready to be built? Or it still requires some updates/fixes? I would build a tnCart board to compare with WonderTANG! if it is considered ok to get built in its current status. Do you plan to publish the complete rev2 kicad design files, besides the schematic?

Sorry, work has been busy and no progress has been made on the rev2 board. I am reconsidering whether an I2S DAC is more advantageous in terms of cost and board space occupied than a PDM + active filter.

herraa1 commented 3 weeks ago

Sorry, work has been busy and no progress has been made on the rev2 board. I am reconsidering whether an I2S DAC is more advantageous in terms of cost and board space occupied than a PDM + active filter.

Thanks for your feedback.

Yes, there are lots of cheap I2S DAC modules out there. Using one of those would be cheaper (and easier to solder for hobbyists) than sourcing specific components for the active filter (if it is not a trivial one).