// ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014,2019
//
// fpga SPI slave device -- AVR controlled.
/*
This file is part of ZX-Evo Base Configuration firmware.
ZX-Evo Base Configuration firmware is free software:
you can redistribute it and/or modify it under the terms of
the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ZX-Evo Base Configuration firmware is distributed in the hope that
it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ZX-Evo Base Configuration firmware.
If not, see <http://www.gnu.org/licenses/>.
*/
`include "../include/tune.v"
module slavespi(
input wire fclk,
input wire rst_n,
input wire spics_n, // avr SPI iface
output wire spidi, //
input wire spido, //
input wire spick, //
input wire [ 7:0] status_in, // status bits to be shown to avr
output wire [39:0] kbd_out,
output wire kbd_stb,
output wire [ 7:0] mus_out,
output wire mus_xstb,
output wire mus_ystb,
output wire mus_btnstb,
output wire kj_stb,
input wire [ 7:0] gluclock_addr,
input wire [ 2:0] comport_addr,
input wire [ 7:0] wait_write,
output wire [ 7:0] wait_read,
input wire wait_rnw,
output wire wait_end,
output wire [ 7:0] config0, // config bits for overall system
// output wire [ 7:0] config1, //
output wire genrst, // positive pulse, causes Z80 reset
output wire sd_lock_out, // SDcard control iface
input wire sd_lock_in, //
output wire sd_cs_n, //
output wire sd_start, //
output wire [ 7:0] sd_datain, //
input wire [ 7:0] sd_dataout //
);
`ifdef SIMULATE
initial
begin
force wait_read = 8'h00;
end
`endif
// re-synchronize SPI
//
reg [2:0] spics_n_sync;
reg [1:0] spido_sync;
reg [2:0] spick_sync;
//
always @(posedge fclk)
begin
spics_n_sync[2:0] <= { spics_n_sync[1:0], spics_n };
spido_sync [1:0] <= { spido_sync [0], spido };
spick_sync [2:0] <= { spick_sync [1:0], spick };
end
//
wire scs_n = spics_n_sync[1]; // scs_n - synchronized CS_N
wire sdo = spido_sync[1];
wire sck = spick_sync[1];
//
wire scs_n_01 = (~spics_n_sync[2]) & spics_n_sync[1] ;
wire scs_n_10 = spics_n_sync[2] & (~spics_n_sync[1]);
//
wire sck_01 = (~spick_sync[2]) & spick_sync[1] ;
wire sck_10 = spick_sync[2] & (~spick_sync[1]);
reg [7:0] regnum; // register number holder
reg [7:0] shift_out;
reg [7:0] data_in;
// register selectors
wire sel_kbdreg, sel_kbdstb, sel_musxcr, sel_musycr, sel_musbtn, sel_kj,
sel_rstreg, sel_waitreg, sel_gluadr, sel_comadr, sel_cfg0, sel_cfg1,
sel_sddata, sel_sdctrl;
// keyboard register
reg [39:0] kbd_reg;
// common single-byte shift-in register
reg [7:0] common_reg;
// wait data out register
reg [7:0] wait_reg;
//
reg [7:0] cfg0_reg_out;
// reg [7:0] cfg1_reg_out;
// SDcard access registers
reg [7:0] sddata; // output to SDcard
reg [1:0] sdctrl; // SDcard control (CS_n and lock)
`ifdef SIMULATE
initial
begin
cfg0_reg_out[7:0] = 8'd0;
end
`endif
// register number
//
always @(posedge fclk)
begin
if( scs_n_01 )
begin
regnum <= 8'd0;
end
else if( scs_n && sck_01 )
begin
regnum[7:0] <= { sdo, regnum[7:1] };
end
end
// send data to avr
//
always @*
case(1'b1)
sel_waitreg: data_in = wait_write;
sel_gluadr: data_in = gluclock_addr;
sel_comadr: data_in = comport_addr;
sel_sddata: data_in = sd_dataout;
sel_sdctrl: data_in = { sd_lock_in, 7'bXXX_XXXX };
default: data_in = 8'bXXXX_XXXX;
endcase
//
always @(posedge fclk)
begin
if( scs_n_01 || scs_n_10 ) // both edges
begin
shift_out <= scs_n ? status_in : data_in;
end
else if( sck_01 )
begin
shift_out[7:0] <= { 1'b0, shift_out[7:1] };
end
end
//
assign spidi = shift_out[0];
// reg number decoding
//
assign sel_kbdreg = ( (regnum[7:4]==4'h1) && !regnum[0] ); // $10
assign sel_kbdstb = ( (regnum[7:4]==4'h1) && regnum[0] ); // $11
//
assign sel_musxcr = ( (regnum[7:4]==4'h2) && !regnum[1] && !regnum[0] ); // $20
assign sel_musycr = ( (regnum[7:4]==4'h2) && !regnum[1] && regnum[0] ); // $21
assign sel_musbtn = ( (regnum[7:4]==4'h2) && regnum[1] && !regnum[0] ); // $22
assign sel_kj = ( (regnum[7:4]==4'h2) && regnum[1] && regnum[0] ); // $23
//
assign sel_rstreg = ( (regnum[7:4]==4'h3) ) ; // $30
//
assign sel_waitreg = ( (regnum[7:4]==4'h4) && (regnum[1:0]==2'b00) ); // $40
assign sel_gluadr = ( (regnum[7:4]==4'h4) && (regnum[1:0]==2'b01) ); // $41
assign sel_comadr = ( (regnum[7:4]==4'h4) && (regnum[1:0]==2'b10) ); // $42
//
// assign sel_cfg0 = (regnum[7:4]==4'h5 && regnum[0]==1'b0); // $50
// assign sel_cfg1 = (regnum[7:4]==4'h5 && regnum[0]==1'b1); // $51
assign sel_cfg0 = (regnum[7:4]==4'h5); // $50
//
assign sel_sddata = ( (regnum[7:4]==4'h6) && !regnum[0] ); // $60
assign sel_sdctrl = ( (regnum[7:4]==4'h6) && regnum[0] ); // $61
// registers data-in
//
always @(posedge fclk)
begin
// kbd data shift-in
if( !scs_n && sel_kbdreg && sck_01 )
kbd_reg[39:0] <= { sdo, kbd_reg[39:1] };
// mouse data shift-in
if( !scs_n && (sel_musxcr || sel_musycr || sel_musbtn || sel_kj) && sck_01 )
common_reg[7:0] <= { sdo, common_reg[7:1] };
// wait read data shift-in
if( !scs_n && sel_waitreg && sck_01 )
wait_reg[7:0] <= { sdo, wait_reg[7:1] };
// config shift-in
// if( !scs_n && (sel_cfg0 || sel_cfg1) && sck_01 )
if( !scs_n && sel_cfg0 && sck_01 )
common_reg[7:0] <= { sdo, common_reg[7:1] };
// config output
if( scs_n_01 && sel_cfg0 )
cfg0_reg_out <= common_reg;
// if( scs_n_01 && sel_cfg1 )
// cfg1_reg_out <= common_reg;
// SD data shift-in
if( !scs_n && sel_sddata && sck_01 )
common_reg[7:0] <= { sdo, common_reg[7:1] };
// SD control shift-in
if( !scs_n && sel_sdctrl && sck_01 )
common_reg[7:0] <= { sdo, common_reg[7:1] };
end
//
// SD control output
always @(posedge fclk, negedge rst_n)
if( !rst_n )
sdctrl <= 2'b01;
else // posedge clk
begin
if( scs_n_01 && sel_sdctrl )
sdctrl <= { common_reg[7], common_reg[0] };
end
// output data
assign kbd_out = kbd_reg;
assign kbd_stb = sel_kbdstb && scs_n_01;
assign mus_out = common_reg;
assign mus_xstb = sel_musxcr && scs_n_01;
assign mus_ystb = sel_musycr && scs_n_01;
assign mus_btnstb = sel_musbtn && scs_n_01;
assign kj_stb = sel_kj && scs_n_01;
assign genrst = sel_rstreg && scs_n_01;
assign wait_read = wait_reg;
assign wait_end = sel_waitreg && scs_n_01;
assign config0 = cfg0_reg_out;
// assign config1 = cfg1_reg_out;
// SD control output
assign sd_lock_out = sdctrl[1];
assign sd_cs_n = sdctrl[0];
// SD data output
assign sd_datain = common_reg;
// SD start strobe
assign sd_start = sel_sddata && scs_n_01;
endmodule