Quantcast
Channel: Altera Forums
Viewing all articles
Browse latest Browse all 19390

Mysterious trouble sharing FPGA RAM with HPS

$
0
0
Hello all
I'm a hobbyist and I'm trying to learn verilog and FPGA design by building a PDP-8 simulator. I've built the verilog for the PDP8 and it passes all the test code when run on a simulator.

I'm now trying to build it into the DE1-SoC so that the HPS can, via a program written in c, load PDP8 code into the RAM on the FPGA, start the PDP8 CPU which lives on the FPGA and communicate with the PDP8 on the FPGA via a terminal interface.

My problems are at the first integration step. I have a verilog module pdp8_RAM.v which I hope to have built to be a dual-port RAM that is shared by the HPS and the FPGA-PDP8. The code is below:

Code:

module pdp8_RAM (
    // inputs:
    //  from HPS bridge
    address,
    clk,
    chipselect,
    reset_n,
    write_n,
    writedata,
    //  from PDP8 CPU
    pdp8_clk_from_CPU,
    pdp8_reset_from_CPU,
    pdp8_addr_from_CPU,
    pdp8_DI_from_CPU,
    pdp8_start_RD_from_CPU,
    pdp8_start_WR_from_CPU,
   
    // outputs:
    //  to HPS bridge
    readdata, //,
    //  to PDP8 CPU
    pdp8_DO_to_CPU,
    pdp8_RAM_CC_to_CPU
);


input[14:0] address;
input clk;
input chipselect;
input reset_n;
input write_n;
input[15:0] writedata;
input pdp8_clk_from_CPU;
input pdp8_reset_from_CPU;
input[14:0] pdp8_addr_from_CPU;
input[11:0] pdp8_DI_from_CPU;
input pdp8_start_RD_from_CPU;
input pdp8_start_WR_from_CPU;


output reg[15:0] readdata;


output reg[11:0] pdp8_DO_to_CPU;
output wire pdp8_RAM_CC_to_CPU;


reg[15:0] ram [0:32767];
reg busy;
assign pdp8_RAM_CC_to_CPU = ~busy;


// HPS RAM access
always @ (posedge clk or negedge reset_n)
begin
    if (!reset_n)
        readdata <= 0;
    else if (chipselect && !write_n)
          ram[address] <= writedata;
    else
        readdata <= ram[address];
end


// PDP8 RAM access
always @ (posedge pdp8_clk_from_CPU or posedge pdp8_reset_from_CPU)
begin
    if (pdp8_reset_from_CPU)
        begin
            pdp8_DO_to_CPU <= 0;
            busy <= 1'b0;
        end
    else
        begin
            pdp8_DO_to_CPU <= ram[pdp8_addr_from_CPU][11:0];
            if (pdp8_start_RD_from_CPU)
                busy <= 1'b1;
            else if (pdp8_start_WR_from_CPU)
                begin
                    ram[pdp8_addr_from_CPU] <= {4'b0, pdp8_DI_from_CPU};
                    busy <= 1'b1;
                end
            else
                busy <= 1'b0;
        end
end


initial
begin
  ram[15'o00000] = 12'o1000; TAD 0 (ac = 1000)
  ram[15'o00001] = 12'o7040; CMA (ac = 6777)
  ram[15'o00002] = 12'o7402; HLT
end


endmodule

This is wired to the PDP8 CPU on the FPGA and I know these connections work because, if I run it at 1Hz, the LEDs and 7-segment display I've connected to the PDP8 CPU show that it nicely steps through and halts at the HLT at location 00002.

Things get weird when I try to alter the RAM from the HPS.

I used platform designer to hook it up to the GHRD as shown in the figure on the left.

I can build the system and the CPU runs the pre-loaded code in the RAM.

If I try to access the RAM from the HPS, using the code below (I'm only showing the relevant parts - please forgive the ugliness, I'm entirely self-taught on this stuff):
First, the pointer to the RAM:
Code:

<snip>
uint16_t volatile *ram_base_pointer;
<snip>
        h2p_pdp8_ram_addr = virtual_base +
        ( ( unsigned long  )( ALT_LWFPGASLVS_OFST + PDP8_RAM_0_BASE )
        & ( unsigned long)( HW_REGS_MASK ) );
        ram_base_pointer = (uint16_t volatile *)h2p_pdp8_ram_addr;
<snip>
void show_memory() {
    printf("\t  0\t  1\t  2\t  3\t  4\t  5\t  6\t  7\n");
    int i;
    for (i = 0; i < 128; i++) {
        if ((i % 8) == 0) {
            printf("%.5o:\t", display_address_pointer);
        }
        printf("%.4o\t", *(ram_base_pointer + display_address_pointer));
        display_address_pointer++;
        if ((i % 8) == 7) {
            printf("\n");
        }
    }
}
<snip>
uint16_t four_digit_ascii_to_octal(char *s, int offset) {
    int i;
    uint16_t result = 0;
    for (i = offset; i < (offset + 4); i++) {
        result = result + ((s[i] - 48) << ((9 + (3 * offset)) - (3 * i)));
    }
    return result;
}
<snip>
void edit_memory() {
    while(1) {
        printf("%.4o?", entry_address_pointer);
        scanf("%s", in_string);
        if (in_string[0] == 'x') {
            return;
        } else {
            *(ram_base_pointer + entry_address_pointer) = four_digit_ascii_to_octal(in_string, 0);
            entry_address_pointer++;
        }
    }
}

Immediately after programming the FPGA, if I run the code above - especially the function show_memory(), I see what I would expect to see - shown in the second image).

If I edit the memory using the function edit_memory(), it shows the memory as edited. HOWEVER - the CPU behaves as if the memory had not been edited! If I reboot linux and re-run the program, it reports the edited RAM contents. Oddly, if I leave the program running, re-program the FPGA, and read the RAM from the HPS, I now see the original RAM contents.

So, there's some strange disconnect between the RAM on the FPGA and the RAM that the HPS sees. Sometimes, the HPS reads it correctly - when the FPGA is freshly-programmed; other times, like after I've edited the "RAM", the HPS sees it as changed but the FPGA doesn't. It's making me crazy...

I tried adding the volatile qualifier to no effect - but I may be using it wrong.

Please forgive the amateur newbie question; I'm sorry for all the detail and for anything important that I left out.

Any suggestions would be greatly appreciated.

Thanks
Brian


Attached Images

Viewing all articles
Browse latest Browse all 19390

Trending Articles