// 写优先: 立即把当前din写入值 输出到dout接口, 相当于把din和dout连接起来了
// 读优先: 如果本身没有值会直接输出din到dout接口, 如果由值, 会把旧的值输出到dout接口
// 不做任何改变: din和dout接口没有相关性

// 该实验会在复位之后启动ram核, 然后一个计数器累加从0~15, 其中0~7的时候高电平进行写(同样写0~7), 8~15低电平进行读取(把写的读出来)
module ram(
    (*mark_debug="true"*)input wire sys_clk,  // U18
    (*mark_debug="true"*)input wire sys_rst  //J15
);


(*mark_debug="true"*)reg [2:0]ram_addr;  // 数据深度为8, 地址变化范围 0~7就行了, 每个时钟周期加1, 直到溢出从0开始
(*mark_debug="true"*)reg [2:0]in_ram_data;  // 数据宽度为3, 假想写入的数据, 数据变化范围是0~7, 只有在 ram_rw 是写入的时候进行累加并写入地址内
(*mark_debug="true"*)wire [2:0]out_ram_data;

reg ram_en;  
always @(posedge sys_clk or negedge sys_rst) begin
    if (!sys_rst) begin
        ram_en <= 1'b0;
    end
    // 只有在复位之后, 才允许启动ram
    else begin
        ram_en <= 1'b1;
    end
end


(*mark_debug="true"*)reg [7:0]counter;  // 计数到15 清零, 变化范围 0~15, 0~7是写, 8~15是读
wire ram_rw;  // 是否可写/可读
(*mark_debug="true"*)assign ram_rw = ram_en && (counter <= 8'b111);  // 计数器 分成读写各占一半时间
always @(posedge sys_clk or negedge sys_rst) begin
    if (!sys_rst) begin
        counter <= 8'b0;
    end
    // 没有启用ram禁止计数
    else if (ram_en == 1'b0 || counter == 8'b1111) begin
        counter <= 8'b0;
    end
    else begin
        counter <= counter + 8'b1;
    end
end

always @(posedge sys_clk or negedge sys_rst) begin
    if (!sys_rst) begin
        ram_addr <= 3'b0;
    end
    else if (ram_en && ram_addr < 3'b111) begin
        ram_addr <= ram_addr + 3'b1;
    end
    else begin
        ram_addr <= 3'b0;
    end
end


always @(posedge sys_clk or negedge sys_rst) begin
    if (!sys_rst) begin
        in_ram_data <= 3'b0;
    end
    // 如果是写, 并且还没到最大数
    else if (ram_rw && in_ram_data < 3'b111) begin
        in_ram_data <= in_ram_data + 3'b1;
    end
    else begin
        in_ram_data <= 3'b0;
    end
end


blk_mem_gen_0 _blk_mem_gen_0 (
  .clka(sys_clk),    // input wire clka
  .ena(ram_en),      // input wire ena
  .wea(ram_rw),      // input wire [0 : 0] wea
  .addra(ram_addr),  // input wire [2 : 0] addra
  .dina(in_ram_data),    // input wire [2 : 0] dina
  .douta(out_ram_data)  // output wire [2 : 0] douta
);

endmodule