Ram / Rom Timing Question

Discussion of developmental aspects of the MiSTer Project.
nico24
Posts: 64
Joined: Mon May 25, 2020 12:18 am
Has thanked: 32 times
Been thanked: 52 times

Ram / Rom Timing Question

Unread post by nico24 »

I put together an actual 65C02 chip with 32kb of Ram and 32kb of Rom.

In the ROM I placed a few bytes of test code:
At FFFC 00, FFFD 80 - the reset vector to point to address 8000 to start the code
I won't bore with the code but essentially load 42 into the accumulator, and then load address 2000 and write the number 42 to address 2000. It then does a few other things.

So I've been trying to simulate this in Verilog - first try works ok - like this:

Code: Select all

module CPU6502TEST_top;

    reg clk=0;              
    reg rst_n=0;              
	reg cpu_clken=0;

    wire [15:0] ab;
    reg  [7:0] dbi;
    wire [7:0] dbo;
    wire we;
	reg [7:0] ram[0:32767];
	reg [7:0] rom[0:32767];
	
	initial begin
		$readmemh("rom.txt", rom, 0, 32767);
	end

   cpu c6502(
    .clk(clk),
	.reset(!rst_n),
	.AB(ab),
	.DI(dbi),
	.DO(dbo),
	.WE(we),
	.IRQ(1'b0),
	.NMI(1'b0),
	.RDY(1'b1),
	.PC_MONITOR()
  );

always @(posedge clk)
  begin
    casez (ab)
	  16'b0zzzzzzzzzzzzzzz: dbi <= ram[ab[14:0]];
	  16'b1zzzzzzzzzzzzzzz: dbi <= rom[ab[14:0]];
	endcase
  end

always @(posedge clk)
  if (we) begin
    casez (ab)
	  16'b0zzzzzzzzzzzzzzz: ram[ab[14:0]] <= dbo;
	endcase
  end
 
initial
  begin
    $dumpfile("dump.vcd");
    $dumpvars(1);
#1 rst_n=1'b1;
#3 rst_n=1'b0;   
#10 rst_n=1'b1;
#150 $finish;
  end

always #1 clk=~clk;

endmodule
This gives the simulated output of:
trace1.jpg
trace1.jpg (82.3 KiB) Viewed 1828 times
So I would like to make it in line with code I have seen used for other FPGA implementations as below:

Code: Select all

module CPU6502TEST_top;

    reg clk=0;               // 25 MHz master clock
    reg rst_n=0;               // active low synchronous reset (needed for simulation) 
	reg cpu_clken=0;

   //////////////////////////////////////////////////////////////////////////
    // Registers and Wires

    wire [15:0] ab;
	wire [7:0] dbi;
    wire [7:0] dbo;
    wire we;

    //////////////////////////////////////////////////////////////////////////
    // 6502

   cpu c6502(
    .clk(clk),
	.reset(!rst_n),
	.AB(ab),
	.DI(dbi),
	.DO(dbo),
	.WE(we),
	.IRQ(1'b0),
	.NMI(1'b0),
	.RDY(1'b1),
	.PC_MONITOR()
  );
  
    // Address Decoding

    wire ram_cs = (ab[15] == 1'b0);
    wire rom_cs = (ab[15] == 1'b1);

    // RAM
    wire [7:0] ram_dout;
	ram icB1(
        .clk(clk),
        .address(ab[14:0]),
        .w_en(we & ram_cs),
        .din(dbo),
        .dout(ram_dout)
    );

    wire [7:0] rom_dout;
	rom icA1(
        .clk(clk),
        .address(ab[14:0]),
        .dout(rom_dout)
    );

//    //////////////////////////////////////////////////////////////////////////
//    // CPU Data In MUX
//
    // link up chip selected device to cpu input
    assign dbi = ram_cs ? ram_dout :
                 rom_cs ? rom_dout :
                 8'hFF;

initial
  begin
    $dumpfile("dump.vcd");
    $dumpvars(1);
#1 rst_n=1'b1;
#3 rst_n=1'b0;   
#10 rst_n=1'b1;
#150 $finish;
  end

always #1 clk=~clk;

endmodule

module rom (
    input clk,              // clock signal
    input [14:0] address,   // address bus
    output reg [7:0] dout   // 8-bit data bus (output)
);

    reg [7:0] rom_data[0:32767];

    initial
        $readmemh("rom.txt", rom_data, 0, 32767);

    always @(posedge clk)
        dout <= rom_data[address];

endmodule

module ram (
    input clk,              // clock signal
    input [14:0] address,   // address bus
    input w_en,             // active high write enable strobe
    input [7:0] din,        // 8-bit data bus (input)
    output reg [7:0] dout   // 8-bit data bus (output)
);

    reg [7:0] ram_data[0:32767];

    initial
        $readmemh("ram.txt", ram_data, 0, 32767);

    always @(posedge clk)
    begin
        dout <= ram_data[address];
        if (w_en) ram_data[address] <= din;
    end

endmodule
But this gives the trace at the underneath:

You can see that after 8004 it is not picking up the 20 to go to address 2000, so instead goes to address 0000.

Any idea what I need to change in the code for the second example to make it behave like the first?

I'm sure it's to do with additional clock cycles, but I've been banging my head against a wall for this for far too long.

thanks
Attachments
trace2.jpg
trace2.jpg (103.17 KiB) Viewed 1841 times
paulbnl
Core Developer
Posts: 168
Joined: Sun May 24, 2020 8:48 pm
Has thanked: 15 times
Been thanked: 113 times

Re: Ram / Rom Timing Question

Unread post by paulbnl »

You need to consider when the CPU reads the data. A real 6502 sets the address at the falling edge and reads data at the rising edge of the clock.

I think in your simulation the CPU reads data on a falling edge but it looks like the trace only samples data on the rising edge of the clock. It needs to show every data change so you can see what is happening to the address and ram/rom_cs at the falling edges.
nico24
Posts: 64
Joined: Mon May 25, 2020 12:18 am
Has thanked: 32 times
Been thanked: 52 times

Re: Ram / Rom Timing Question

Unread post by nico24 »

Thanks Paul.
grizzly
Posts: 304
Joined: Tue Jun 16, 2020 12:22 pm
Has thanked: 33 times
Been thanked: 44 times

Re: Ram / Rom Timing Question

Unread post by grizzly »

Yeah thanks paul!
Not that i understand any of this anyway :mrgreen:
Post Reply