// part of NeoGS flash programmer project (c) 2014 lvd^NedoPC
//
// rom controller
//
// !!!!!!!!!!!enables addr bus as soon as reset is removed!!!!!!!
module rom
(
input wire clk,
input wire rst_n,
input wire wr_addr,
input wire wr_data,
input wire rd_data,
input wire [ 7:0] wr_buffer,
output reg [ 7:0] rd_buffer,
input wire autoinc_ena,
output wire [18:0] rom_a,
inout wire [ 7:0] rom_d,
output reg rom_cs_n,
output reg rom_oe_n,
output reg rom_we_n
);
reg [7:0] wrdata;
wire [7:0] rddata;
reg enadata;
reg [18:0] addr;
reg [18:0] next_addr;
reg enaaddr;
reg [2:0] addr_phase;
reg rnw;
reg [6:0] rw_phase;
// dbus control
assign rom_d = enadata ? wrdata : 8'bZZZZ_ZZZZ;
assign rddata = rom_d;
// abus control
assign rom_a = enaaddr ? addr : {19{1'bZ}};
// enaaddr control
always @(posedge clk, negedge rst_n)
if( !rst_n )
enaaddr <= 1'b0;
else
enaaddr <= 1'b1;
// address phase (points which one of 3byte address to write into)
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
addr_phase <= 3'b001;
end
else
case( {wr_addr, wr_data, rd_data} )
3'b100: addr_phase <= {addr_phase[1:0], addr_phase[2] };
3'b010,3'b001: addr_phase <= 3'b001;
default: addr_phase <= addr_phase;
endcase
// address control
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
next_addr <= 19'd0;
end
else
case( {wr_addr, wr_data, rd_data} )
3'b100: begin
next_addr[ 7:0 ] <= addr_phase[0] ? wr_buffer[7:0] : next_addr[ 7:0 ];
next_addr[15:8 ] <= addr_phase[1] ? wr_buffer[7:0] : next_addr[15:8 ];
next_addr[18:16] <= addr_phase[2] ? wr_buffer[2:0] : next_addr[18:16];
end
3'b010, 3'b001: if( autoinc_ena ) next_addr <= next_addr + 19'd1;
default: next_addr <= next_addr;
endcase
// address output register
always @(posedge clk)
if( wr_data || rd_data )
addr <= next_addr;
// read/write sequence
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
rw_phase <= 'd0;
rnw <= 1'b1;
end
else if( rd_data || wr_data )
begin
rw_phase <= 'd1;
rnw <= rd_data;
end
else
begin
rw_phase <= rw_phase<<1;
end
// output control
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
enadata <= 1'b0;
end
else if( rw_phase[0] )
begin
enadata <= !rnw;
end
else if( rw_phase[6] )
begin
enadata <= 1'b0;
end
//
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
rom_cs_n <= 1'b1;
rom_oe_n <= 1'b1;
rom_we_n <= 1'b1;
end
else if( rw_phase[1] )
begin
rom_cs_n <= 1'b0;
rom_oe_n <= !rnw;
rom_we_n <= rnw;
end
else if( rw_phase[6] )
begin
rom_cs_n <= 1'b1;
rom_oe_n <= 1'b1;
rom_we_n <= 1'b1;
end
//
always @(posedge clk)
if( wr_data )
wrdata <= wr_buffer;
// input control
always @(posedge clk)
if( rw_phase[6] && rnw )
rd_buffer <= rddata;
endmodule