// part of NeoGS flash programmer project (c) 2014 lvd^NedoPC
//
// zxbus controller
module zxbus
(
input wire clk,
input wire rst_n,
inout wire [7:0] zxid, // zxbus DATA BUS in/out [7:0]
input wire [7:0] zxa, // zxbus ADDRESS 7-0 in [7:0]
input wire zxiorq_n,
input wire zxmreq_n,
input wire zxrd_n,
input wire zxwr_n,
output wire zxblkiorq_n, // active low - signal to generate IORQGE
output reg zxbusin, // controls 74hct245 buffer direction (1 - input from bus, 0 - output to zx)
output reg zxbusena_n, // 74hct245 buffer enable signal
output reg init, // positive pulse to cause reset/init to all board
input wire init_in_progress, // 1 while init in progress
output reg led, // LED state
output reg autoinc_ena, // enable autoincrement
output reg wr_addr, // to ROM controller
output reg wr_data, //
output reg rd_data, //
output reg [7:0] wr_buffer, //
input wire [7:0] rd_buffer //
);
wire iowr = ~(zxiorq_n | zxwr_n);
wire iord = ~(zxiorq_n | zxrd_n);
reg [2:0] iowr_r;
reg [2:0] iord_r;
wire iowr_begin, iowr_end;
wire iord_begin, iord_end;
wire io_begin, io_end;
wire addr_ok;
reg wrr;
wire [1:0] regsel;
reg [7:0] read_data;
reg zxid_oe;
reg [7:0] zxid_out;
wire [7:0] zxid_in;
reg [8:0] test_reg;
reg [7:0] test_reg_pre;
reg test_reg_write;
// register select (one of 4)
assign regsel[1:0] = { zxa[7], zxa[3] };
// addr decode
assign addr_ok = (zxa==8'h33) || (zxa==8'h3B) || (zxa==8'hB3) || (zxa==8'hBB);
// IORQGE
assign zxblkiorq_n = ~addr_ok;
// internal data bus control
assign zxid = zxid_oe ? zxid_out : 8'bZZZZ_ZZZZ;
//
assign zxid_in = zxid;
// resync strobes
always @(posedge clk)
begin
iowr_r[2:0] <= { iowr_r[1:0], iowr };
iord_r[2:0] <= { iord_r[1:0], iord };
end
//
assign iowr_begin = iowr_r[1] && !iowr_r[2];
assign iord_begin = iord_r[1] && !iord_r[2];
//
assign iowr_end = !iowr_r[1] && iowr_r[2];
assign iord_end = !iord_r[1] && iord_r[2];
//
assign io_begin = iowr_begin || iord_begin;
assign io_end = iowr_end || iord_end;
// control ext bus buffer
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
zxbusin <= 1'b1;
zxbusena_n <= 1'b1;
end
else if( addr_ok && io_begin )
begin
zxbusin <= ~iord_begin;
zxbusena_n <= 1'b0;
end
else if( io_end )
begin
zxbusena_n <= 1'b1;
end
// control int bus buffer
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
zxid_oe <= 1'b0;
end
else if( addr_ok && io_begin )
begin
zxid_oe <= iord_begin;
end
else if( io_end )
begin
zxid_oe <= 1'b0;
end
// internal write strobe
always @(posedge clk, negedge rst_n)
if( !rst_n )
wrr <= 1'b0;
else
wrr <= addr_ok && iowr_begin;
// write to 33 (init/ctrl reg)
//
always @(posedge clk, negedge rst_n)
if( !rst_n )
led <= 1'b0;
else if( init )
led <= 1'b0;
else if( wrr && regsel==2'b00 && zxid[6] )
led <= ~led;
//
always @(posedge clk, negedge rst_n)
if( !rst_n )
init <= 1'b0;
else if( wrr && regsel==2'b00 && zxid[7] )
init <= 1'b1;
else
init <= 1'b0;
//
always @(posedge clk, negedge rst_n)
if( !rst_n )
autoinc_ena <= 1'b0;
else if( wrr && regsel==2'b00 )
autoinc_ena <= zxid[5];
// write to 3B (test reg)
always @(posedge clk, negedge rst_n)
if( !rst_n )
begin
test_reg <= 9'd0;
end
else if( init )
begin
test_reg <= 9'd0;
end
else if( test_reg_write )
begin
test_reg[8:0] <= { (~test_reg_pre[7:0]), test_reg[8] };
end
//
always @(posedge clk)
if( wrr && regsel==2'b01 )
begin
test_reg_pre <= zxid_in;
test_reg_write <= 1'b1;
end
else
begin
test_reg_write <= 1'b0;
end
// write to B3 (addr reg)
always @(posedge clk)
if( wrr && regsel==2'b10 )
wr_addr <= 1'b1;
else
wr_addr <= 1'b0;
// write to BB (data reg)
always @(posedge clk)
if( wrr && regsel==2'b11 )
wr_data <= 1'b1;
else
wr_data <= 1'b0;
// read from BB (data reg)
always @(posedge clk)
if( addr_ok && regsel==2'b11 && iord_begin )
rd_data <= 1'b1;
else
rd_data <= 1'b0;
// write data for B3 and BB
always @(posedge clk)
if( wrr && regsel[1]==1'b1 )
wr_buffer <= zxid_in;
// ports read
always @*
case( regsel )
2'b00: read_data = { init_in_progress, 7'd0 };
2'b01: read_data = test_reg[7:0];
//2'b10: read_data <= рег адреса (НОЛЬ!)
2'b11: read_data = rd_buffer;
default: read_data = 8'd0;
endcase
//
always @(posedge clk)
if( addr_ok && iord_begin )
zxid_out <= read_data;
endmodule