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
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
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