From a3c2f83e1bf095dcf0ae008530a183eaca07e596 Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Thu, 6 Sep 2018 02:07:09 +0200 Subject: [PATCH] C64: update mist_io for synchronizing SPI_SCK->clk_sys --- cores/c64/rtl/c64_mist.vhd | 2 + cores/c64/rtl/mist_io.v | 550 +++++++++++++++++++++++-------------- 2 files changed, 347 insertions(+), 205 deletions(-) diff --git a/cores/c64/rtl/c64_mist.vhd b/cores/c64/rtl/c64_mist.vhd index f5c10a8..338dca8 100644 --- a/cores/c64/rtl/c64_mist.vhd +++ b/cores/c64/rtl/c64_mist.vhd @@ -155,6 +155,7 @@ end function; component mist_io generic(STRLEN : integer := 0 ); port ( clk_sys : in std_logic; + clk_sd : in std_logic; SPI_SCK : in std_logic; CONF_DATA0 : in std_logic; @@ -509,6 +510,7 @@ begin generic map (STRLEN => CONF_STR'length) port map ( clk_sys => clk32, + clk_sd => clk32, SPI_SCK => SPI_SCK, CONF_DATA0 => CONF_DATA0, diff --git a/cores/c64/rtl/mist_io.v b/cores/c64/rtl/mist_io.v index 107c0f6..5b47e96 100644 --- a/cores/c64/rtl/mist_io.v +++ b/cores/c64/rtl/mist_io.v @@ -38,6 +38,7 @@ module mist_io #(parameter STRLEN=0, parameter PS2DIV=100) // Global clock. It should be around 100MHz (higher is better). input clk_sys, + input clk_sd, // Global SPI clock from ARM. 24MHz input SPI_SCK, @@ -61,7 +62,7 @@ module mist_io #(parameter STRLEN=0, parameter PS2DIV=100) // SD config input sd_conf, input sd_sdhc, - output img_mounted, // signaling that new image has been mounted + output reg img_mounted, // signaling that new image has been mounted output reg [31:0] img_size, // size of image in bytes // SD block level access @@ -75,7 +76,7 @@ module mist_io #(parameter STRLEN=0, parameter PS2DIV=100) output reg [8:0] sd_buff_addr, output reg [7:0] sd_buff_dout, input [7:0] sd_buff_din, - output reg sd_buff_wr, + output sd_buff_wr, // ps2 keyboard emulation output ps2_kbd_clk, @@ -94,201 +95,48 @@ module mist_io #(parameter STRLEN=0, parameter PS2DIV=100) output reg [7:0] ioctl_dout ); -reg [7:0] b_data; -reg [6:0] sbuf; -reg [7:0] cmd; -reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... -reg [9:0] byte_cnt; // counts bytes -reg [7:0] but_sw; -reg [2:0] stick_idx; - -reg mount_strobe = 0; -assign img_mounted = mount_strobe; +reg [6:0] sbuf; +reg [7:0] cmd; +reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... +reg [7:0] byte_cnt; // counts bytes +reg [5:0] joystick0; +reg [5:0] joystick1; +reg [7:0] but_sw; +reg [2:0] stick_idx; assign buttons = but_sw[1:0]; assign switches = but_sw[3:2]; assign scandoubler_disable = but_sw[4]; assign ypbpr = but_sw[5]; -wire [7:0] spi_dout = { sbuf, SPI_DI}; - // this variant of user_io is for 8 bit cores (type == a4) only wire [7:0] core_type = 8'ha4; // command byte read by the io controller wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd }; +wire spi_sck = SPI_SCK; + reg spi_do; assign SPI_DO = CONF_DATA0 ? 1'bZ : spi_do; -wire [7:0] kbd_led = { 2'b01, 4'b0000, ps2_caps_led, 1'b1}; +// ---------------- PS2 --------------------- -// drive MISO only when transmitting core id -always@(negedge SPI_SCK) begin - if(!CONF_DATA0) begin - // first byte returned is always core type, further bytes are - // command dependent - if(byte_cnt == 0) begin - spi_do <= core_type[~bit_cnt]; - - end else begin - case(cmd) - // reading config string - 8'h14: begin - // returning a byte from string - if(byte_cnt < STRLEN + 1) spi_do <= conf_str[{STRLEN - byte_cnt,~bit_cnt}]; - else spi_do <= 0; - end - - // reading sd card status - 8'h16: begin - if(byte_cnt == 1) spi_do <= sd_cmd[~bit_cnt]; - else if((byte_cnt >= 2) && (byte_cnt < 6)) spi_do <= sd_lba[{5-byte_cnt, ~bit_cnt}]; - else spi_do <= 0; - end - - // reading sd card write data - 8'h18: - spi_do <= b_data[~bit_cnt]; - - // reading keyboard LED status - 8'h1f: - spi_do <= kbd_led[~bit_cnt]; - - default: - spi_do <= 0; - endcase - end - end -end - -reg b_wr2,b_wr3; -always @(negedge clk_sys) begin - b_wr3 <= b_wr2; - sd_buff_wr <= b_wr3; -end - -// SPI receiver -always@(posedge SPI_SCK or posedge CONF_DATA0) begin - - if(CONF_DATA0) begin - b_wr2 <= 0; - bit_cnt <= 0; - byte_cnt <= 0; - sd_ack <= 0; - sd_ack_conf <= 0; - end else begin - b_wr2 <= 0; - - sbuf <= spi_dout[6:0]; - bit_cnt <= bit_cnt + 1'd1; - if(bit_cnt == 5) begin - if (byte_cnt == 0) sd_buff_addr <= 0; - if((byte_cnt != 0) & (sd_buff_addr != 511)) sd_buff_addr <= sd_buff_addr + 1'b1; - if((byte_cnt == 1) & ((cmd == 8'h17) | (cmd == 8'h19))) sd_buff_addr <= 0; - end - - // finished reading command byte - if(bit_cnt == 7) begin - if(~&byte_cnt) byte_cnt <= byte_cnt + 8'd1; - if(byte_cnt == 0) begin - cmd <= spi_dout; - - if(spi_dout == 8'h19) begin - sd_ack_conf <= 1; - sd_buff_addr <= 0; - end - if((spi_dout == 8'h17) || (spi_dout == 8'h18)) begin - sd_ack <= 1; - sd_buff_addr <= 0; - end - if(spi_dout == 8'h18) b_data <= sd_buff_din; - - mount_strobe <= 0; - - end else begin - - case(cmd) - // buttons and switches - 8'h01: but_sw <= spi_dout; - 8'h02: joystick_0 <= spi_dout; - 8'h03: joystick_1 <= spi_dout; - - // store incoming ps2 mouse bytes - 8'h04: begin - ps2_mouse_fifo[ps2_mouse_wptr] <= spi_dout; - ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; - end - - // store incoming ps2 keyboard bytes - 8'h05: begin - ps2_kbd_fifo[ps2_kbd_wptr] <= spi_dout; - ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; - end - - 8'h15: status[7:0] <= spi_dout; - - // send SD config IO -> FPGA - // flag that download begins - // sd card knows data is config if sd_dout_strobe is asserted - // with sd_ack still being inactive (low) - 8'h19, - // send sector IO -> FPGA - // flag that download begins - 8'h17: begin - sd_buff_dout <= spi_dout; - b_wr2 <= 1; - end - - 8'h18: b_data <= sd_buff_din; - - // joystick analog - 8'h1a: begin - // first byte is joystick index - if(byte_cnt == 1) stick_idx <= spi_dout[2:0]; - else if(byte_cnt == 2) begin - // second byte is x axis - if(stick_idx == 0) joystick_analog_0[15:8] <= spi_dout; - else if(stick_idx == 1) joystick_analog_1[15:8] <= spi_dout; - end else if(byte_cnt == 3) begin - // third byte is y axis - if(stick_idx == 0) joystick_analog_0[7:0] <= spi_dout; - else if(stick_idx == 1) joystick_analog_1[7:0] <= spi_dout; - end - end - - // notify image selection - 8'h1c: mount_strobe <= 1; - - // send image info - 8'h1d: if(byte_cnt<5) img_size[(byte_cnt-1)<<3 +:8] <= spi_dout; - - // status, 32bit version - 8'h1e: if(byte_cnt<5) status[(byte_cnt-1)<<3 +:8] <= spi_dout; - default: ; - endcase - end - end - end -end - - -/////////////////////////////// PS2 /////////////////////////////// // 8 byte fifos to store ps2 bytes localparam PS2_FIFO_BITS = 3; -reg clk_ps2; +reg ps2_clk; always @(negedge clk_sys) begin - integer cnt; - cnt <= cnt + 1'd1; - if(cnt == PS2DIV) begin - clk_ps2 <= ~clk_ps2; - cnt <= 0; - end + integer cnt; + cnt <= cnt + 1'd1; + if(cnt == PS2DIV) begin + ps2_clk <= ~ps2_clk; + cnt <= 0; + end end // keyboard -reg [7:0] ps2_kbd_fifo[1<= 1)&&(ps2_kbd_tx_state < 9)) begin - ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits + ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down if(ps2_kbd_tx_byte[0]) ps2_kbd_parity <= !ps2_kbd_parity; end // transmission of parity - if(ps2_kbd_tx_state == 9) ps2_kbd_data <= ps2_kbd_parity; - + if(ps2_kbd_tx_state == 9) + ps2_kbd_data <= ps2_kbd_parity; + // transmission of stop bit - if(ps2_kbd_tx_state == 10) ps2_kbd_data <= 1; // stop bit is 1 + if(ps2_kbd_tx_state == 10) + ps2_kbd_data <= 1'b1; // stop bit is 1 // advance state machine - if(ps2_kbd_tx_state < 11) ps2_kbd_tx_state <= ps2_kbd_tx_state + 1'd1; - else ps2_kbd_tx_state <= 0; + if(ps2_kbd_tx_state < 11) + ps2_kbd_tx_state <= ps2_kbd_tx_state + 4'd1; + else + ps2_kbd_tx_state <= 4'd0; end end end // mouse -reg [7:0] ps2_mouse_fifo[1< advance read pointer + if((bit_cnt == 7) && !byte_cnt[0] && serial_out_data_available) + serial_out_rptr <= serial_out_rptr + 1'd1; + end + end +end +*/ + +// SPI bit and byte counters +always@(posedge spi_sck or posedge CONF_DATA0) begin + if(CONF_DATA0 == 1) begin + bit_cnt <= 0; + byte_cnt <= 0; + end else begin + if((bit_cnt == 7)&&(byte_cnt != 8'd255)) + byte_cnt <= byte_cnt + 8'd1; + + bit_cnt <= bit_cnt + 1'd1; + end +end + +// SPI transmitter FPGA -> IO +reg [7:0] spi_byte_out; + +always@(negedge spi_sck or posedge CONF_DATA0) begin + spi_do <= spi_byte_out[~bit_cnt]; +end + +always@(posedge spi_sck or posedge CONF_DATA0) begin + reg [31:0] sd_lba_r; + + if(CONF_DATA0 == 1) begin + spi_byte_out <= core_type; + end else begin + // read the command byte to choose the response + if(bit_cnt == 7) begin + if(!byte_cnt) cmd <= {sbuf, SPI_DI}; + + spi_byte_out <= 0; + case({(!byte_cnt) ? {sbuf, SPI_DI} : cmd}) + // reading config string + 8'h14: if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8]; + + // reading sd card status + 8'h16: if(byte_cnt == 0) begin + spi_byte_out <= sd_cmd; + sd_lba_r <= sd_lba; + end + else if(byte_cnt < 5) spi_byte_out <= sd_lba_r[(4-byte_cnt)<<3 +:8]; + + // reading sd card write data + 8'h18: spi_byte_out <= sd_buff_din; + 8'h1b: + // send alternating flag byte and data + if(byte_cnt[0]) spi_byte_out <= serial_out_status; + else spi_byte_out <= serial_out_byte; + endcase + end + end +end + +// SPI receiver IO -> FPGA + +reg spi_receiver_strobe_r; +reg spi_transfer_end_r; +reg [7:0] spi_byte_in_r; + +// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys +always@(posedge spi_sck or posedge CONF_DATA0) begin + + if(CONF_DATA0 == 1) begin + spi_receiver_strobe_r <= 0; + spi_transfer_end_r <= 1; + end else begin + spi_receiver_strobe_r <= 0; + spi_transfer_end_r <= 0; + + if(bit_cnt != 7) + sbuf[6:0] <= { sbuf[5:0], SPI_DI }; + + // finished reading a byte, prepare to transfer to clk_sys + if(bit_cnt == 7) begin + spi_byte_in_r <= { sbuf, SPI_DI}; + spi_receiver_strobe_r <= 1; + end + end +end + +// Process bytes from SPI at the clk_sys domain +always @(posedge clk_sys) begin + + reg spi_receiver_strobe; + reg spi_transfer_end; + reg [7:0] spi_byte_in; + reg spi_receiver_strobeD; + reg spi_transfer_endD; + reg [7:0] spi_byte_inD; + reg [7:0] acmd; + reg [7:0] abyte_cnt; // counts bytes + + //synchronize between SPI and sys clock domains + spi_receiver_strobeD <= spi_receiver_strobe_r; + spi_receiver_strobe <= spi_receiver_strobeD; + spi_transfer_endD <= spi_transfer_end_r; + spi_transfer_end <= spi_transfer_endD; + spi_byte_inD <= spi_byte_in_r; + spi_byte_in <= spi_byte_inD; + + if (~spi_transfer_endD & spi_transfer_end) begin + abyte_cnt <= 8'd0; + end else if (~spi_receiver_strobeD & spi_receiver_strobe) begin + + if(abyte_cnt != 8'd255) + abyte_cnt <= byte_cnt + 8'd1; + + if(abyte_cnt == 0) begin + acmd <= spi_byte_in; + end else begin + case(acmd) + // buttons and switches + 8'h01: but_sw <= spi_byte_in; + 8'h02: joystick_0 <= spi_byte_in; + 8'h03: joystick_1 <= spi_byte_in; + 8'h04: begin + // store incoming ps2 mouse bytes + ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in; + ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; + end + 8'h05: begin + // store incoming ps2 keyboard bytes + ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in; + ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; + end + + // joystick analog + 8'h1a: begin + // first byte is joystick indes + if(abyte_cnt == 1) + stick_idx <= spi_byte_in[2:0]; + else if(abyte_cnt == 2) begin + // second byte is x axis + if(stick_idx == 0) + joystick_analog_0[15:8] <= spi_byte_in; + else if(stick_idx == 1) + joystick_analog_1[15:8] <= spi_byte_in; + end else if(abyte_cnt == 3) begin + // third byte is y axis + if(stick_idx == 0) + joystick_analog_0[7:0] <= spi_byte_in; + else if(stick_idx == 1) + joystick_analog_1[7:0] <= spi_byte_in; + end + end + + 8'h15: status <= spi_byte_in; + + // status, 32bit version + 8'h1e: if(abyte_cnt<6) status[(abyte_cnt-2)<<3 +:8] <= spi_byte_in; + + endcase + end + end +end + +reg sd_din_strobe; +reg sd_dout_strobe; +assign sd_buff_wr = sd_dout_strobe; + +// Process SD-card related bytes from SPI at the clk_sd domain +always @(posedge clk_sd) begin + + reg spi_receiver_strobe; + reg spi_transfer_end; + reg [7:0] spi_byte_in; + reg spi_receiver_strobeD; + reg spi_transfer_endD; + reg [7:0] spi_byte_inD; + reg [7:0] acmd; + reg [7:0] abyte_cnt; // counts bytes + + //synchronize between SPI and sd clock domains + spi_receiver_strobeD <= spi_receiver_strobe_r; + spi_receiver_strobe <= spi_receiver_strobeD; + spi_transfer_endD <= spi_transfer_end_r; + spi_transfer_end <= spi_transfer_endD; + spi_byte_inD <= spi_byte_in_r; + spi_byte_in <= spi_byte_inD; + + if(sd_dout_strobe) begin + sd_dout_strobe<= 0; + if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; + end + + if(sd_din_strobe) begin + sd_din_strobe<= 0; + if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; + end + + img_mounted <= 0; + + if (~spi_transfer_endD & spi_transfer_end) begin + abyte_cnt <= 8'd0; + sd_ack <= 1'b0; + sd_ack_conf <= 1'b0; + sd_dout_strobe <= 1'b0; + sd_din_strobe <= 1'b0; + sd_buff_addr<= 0; + end else if (~spi_receiver_strobeD & spi_receiver_strobe) begin + + if(abyte_cnt != 8'd255) + abyte_cnt <= byte_cnt + 8'd1; + + if(abyte_cnt == 0) begin + acmd <= spi_byte_in; + + // fetch first byte when sectore FPGA->IO command has been seen + if(spi_byte_in == 8'h18) + sd_din_strobe <= 1'b1; + + if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18)) + sd_ack <= 1'b1; + + end else begin + case(acmd) + + // send sector IO -> FPGA + 8'h17: begin + // flag that download begins + sd_dout_strobe <= 1'b1; + sd_buff_dout <= spi_byte_in; + end + + // send sector FPGA -> IO + 8'h18: sd_din_strobe <= 1'b1; + + // send SD config IO -> FPGA + 8'h19: begin + // flag that download begins + sd_dout_strobe <= 1'b1; + sd_ack_conf <= 1'b1; + sd_buff_dout <= spi_byte_in; + end + + 8'h1c: img_mounted <= 1; + + // send image info + 8'h1d: if(abyte_cnt<6) img_size[(byte_cnt-2)<<3 +:8] <= spi_byte_in; + endcase end end end