diff --git a/cores/zxgate/zx/zx01/data_io.v b/cores/zxgate/zx/zx01/data_io.v new file mode 100644 index 0000000..541b933 --- /dev/null +++ b/cores/zxgate/zx/zx01/data_io.v @@ -0,0 +1,122 @@ +// +// data_io.v +// +// io controller writable ram for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// This source file 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. +// +// This source file 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 this program. If not, see . +// + +module data_io ( + // io controller spi interface + input sck, + input ss, + input sdi, + + output downloading, // signal indicating an active download + output [15:0] size, // number of bytes in input buffer + + // cpu ram interface + input clk, + input we, + input [10:0] a, + input [8:0] din, + output [8:0] dout +); + +parameter START_ADDR = 16'h0000; + +assign size = addr; + +// ********************************************************************************* +// spi client +// ********************************************************************************* + +// this core supports only the display related OSD commands +// of the minimig +reg [6:0] sbuf; +reg [7:0] cmd /* synthesis noprune */; +reg [7:0] data /* synthesis noprune */; +reg [4:0] cnt /* synthesis noprune */; + +reg [15:0] addr /* synthesis noprune */; +reg rclk /* synthesis noprune */; + +localparam UIO_FILE_TX = 8'h53; +localparam UIO_FILE_TX_DAT = 8'h54; + +assign downloading = downloading_reg; +reg downloading_reg = 1'b0; + +// data_io has its own SPI interface to the io controller +always@(posedge sck, posedge ss) begin + if(ss == 1'b1) + cnt <= 5'd0; + else begin + rclk <= 1'b0; + + // don't shift in last bit. It is evaluated directly + // when writing to ram + if(cnt != 15) + sbuf <= { sbuf[5:0], sdi}; + + // increase target address after write + if(rclk) + addr <= addr + 16'd1; + + // count 0-7 8-15 8-15 ... + if(cnt < 15) cnt <= cnt + 4'd1; + else cnt <= 4'd8; + + // finished command byte + if(cnt == 7) + cmd <= {sbuf, sdi}; + + // prepare/end transmission + if((cmd == UIO_FILE_TX) && (cnt == 15)) begin + // prepare + if(sdi) begin + addr <= START_ADDR; + downloading_reg <= 1'b1; + end else + downloading_reg <= 1'b0; + end + + // command 0x54: UIO_FILE_TX + if((cmd == UIO_FILE_TX_DAT) && (cnt == 15)) begin + data <= {sbuf, sdi}; + rclk <= 1'b1; + end + end +end + +// include the embedded dual port ram +data_io_ram data_io_ram ( + // wire up cpu port + .address_a ( a ), + .clock_a ( clk ), + .data_a ( din ), + .wren_a ( we ), + .q_a ( dout ), + + // io controller port + .address_b ( addr[10:0] ), + .clock_b ( rclk ), + .data_b ( {sbuf, sdi} ), + .wren_b ( (cmd == UIO_FILE_TX_DAT) && !ss ) +); + +endmodule \ No newline at end of file diff --git a/cores/zxgate/zx/zx01/data_io_ram.v b/cores/zxgate/zx/zx01/data_io_ram.v new file mode 100644 index 0000000..44bf5a5 --- /dev/null +++ b/cores/zxgate/zx/zx01/data_io_ram.v @@ -0,0 +1,244 @@ +// megafunction wizard: %RAM: 2-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: data_io_ram.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module data_io_ram ( + address_a, + address_b, + clock_a, + clock_b, + data_a, + data_b, + wren_a, + wren_b, + q_a, + q_b); + + input [10:0] address_a; + input [10:0] address_b; + input clock_a; + input clock_b; + input [7:0] data_a; + input [7:0] data_b; + input wren_a; + input wren_b; + output [7:0] q_a; + output [7:0] q_b; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clock_a; + tri0 wren_a; + tri0 wren_b; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [7:0] sub_wire0; + wire [7:0] sub_wire1; + wire [7:0] q_a = sub_wire0[7:0]; + wire [7:0] q_b = sub_wire1[7:0]; + + altsyncram altsyncram_component ( + .clock0 (clock_a), + .wren_a (wren_a), + .address_b (address_b), + .clock1 (clock_b), + .data_b (data_b), + .wren_b (wren_b), + .address_a (address_a), + .data_a (data_a), + .q_a (sub_wire0), + .q_b (sub_wire1), + .aclr0 (1'b0), + .aclr1 (1'b0), + .addressstall_a (1'b0), + .addressstall_b (1'b0), + .byteena_a (1'b1), + .byteena_b (1'b1), + .clocken0 (1'b1), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .eccstatus (), + .rden_a (1'b1), + .rden_b (1'b1)); + defparam + altsyncram_component.address_reg_b = "CLOCK1", + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_input_b = "BYPASS", + altsyncram_component.clock_enable_output_a = "BYPASS", + altsyncram_component.clock_enable_output_b = "BYPASS", + altsyncram_component.indata_reg_b = "CLOCK1", + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 2048, + altsyncram_component.numwords_b = 2048, + altsyncram_component.operation_mode = "BIDIR_DUAL_PORT", + altsyncram_component.outdata_aclr_a = "NONE", + altsyncram_component.outdata_aclr_b = "NONE", + altsyncram_component.outdata_reg_a = "UNREGISTERED", + altsyncram_component.outdata_reg_b = "UNREGISTERED", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", + altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ", + altsyncram_component.widthad_a = 11, + altsyncram_component.widthad_b = 11, + altsyncram_component.width_a = 8, + altsyncram_component.width_b = 8, + altsyncram_component.width_byteena_a = 1, + altsyncram_component.width_byteena_b = 1, + altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK1"; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" +// Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0" +// Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0" +// Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +// Retrieval info: PRIVATE: BlankMemory NUMERIC "1" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "0" +// Retrieval info: PRIVATE: CLRdata NUMERIC "0" +// Retrieval info: PRIVATE: CLRq NUMERIC "0" +// Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0" +// Retrieval info: PRIVATE: CLRrren NUMERIC "0" +// Retrieval info: PRIVATE: CLRwraddress NUMERIC "0" +// Retrieval info: PRIVATE: CLRwren NUMERIC "0" +// Retrieval info: PRIVATE: Clock NUMERIC "5" +// Retrieval info: PRIVATE: Clock_A NUMERIC "0" +// Retrieval info: PRIVATE: Clock_B NUMERIC "0" +// Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" +// Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "1" +// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" +// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" +// Retrieval info: PRIVATE: JTAG_ID STRING "NONE" +// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" +// Retrieval info: PRIVATE: MEMSIZE NUMERIC "16384" +// Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0" +// Retrieval info: PRIVATE: MIFfilename STRING "" +// Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "3" +// Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "0" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "3" +// Retrieval info: PRIVATE: REGdata NUMERIC "1" +// Retrieval info: PRIVATE: REGq NUMERIC "0" +// Retrieval info: PRIVATE: REGrdaddress NUMERIC "0" +// Retrieval info: PRIVATE: REGrren NUMERIC "0" +// Retrieval info: PRIVATE: REGwraddress NUMERIC "1" +// Retrieval info: PRIVATE: REGwren NUMERIC "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0" +// Retrieval info: PRIVATE: UseDPRAM NUMERIC "1" +// Retrieval info: PRIVATE: VarWidth NUMERIC "0" +// Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "8" +// Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "8" +// Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "8" +// Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "8" +// Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "1" +// Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: enable NUMERIC "0" +// Retrieval info: PRIVATE: rden NUMERIC "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK1" +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "BYPASS" +// Retrieval info: CONSTANT: INDATA_REG_B STRING "CLOCK1" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" +// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "2048" +// Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "2048" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "BIDIR_DUAL_PORT" +// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED" +// Retrieval info: CONSTANT: OUTDATA_REG_B STRING "UNREGISTERED" +// Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_NO_NBE_READ" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_B STRING "NEW_DATA_NO_NBE_READ" +// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "11" +// Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "11" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_B NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_B NUMERIC "1" +// Retrieval info: CONSTANT: WRCONTROL_WRADDRESS_REG_B STRING "CLOCK1" +// Retrieval info: USED_PORT: address_a 0 0 11 0 INPUT NODEFVAL "address_a[10..0]" +// Retrieval info: USED_PORT: address_b 0 0 11 0 INPUT NODEFVAL "address_b[10..0]" +// Retrieval info: USED_PORT: clock_a 0 0 0 0 INPUT VCC "clock_a" +// Retrieval info: USED_PORT: clock_b 0 0 0 0 INPUT NODEFVAL "clock_b" +// Retrieval info: USED_PORT: data_a 0 0 8 0 INPUT NODEFVAL "data_a[7..0]" +// Retrieval info: USED_PORT: data_b 0 0 8 0 INPUT NODEFVAL "data_b[7..0]" +// Retrieval info: USED_PORT: q_a 0 0 8 0 OUTPUT NODEFVAL "q_a[7..0]" +// Retrieval info: USED_PORT: q_b 0 0 8 0 OUTPUT NODEFVAL "q_b[7..0]" +// Retrieval info: USED_PORT: wren_a 0 0 0 0 INPUT GND "wren_a" +// Retrieval info: USED_PORT: wren_b 0 0 0 0 INPUT GND "wren_b" +// Retrieval info: CONNECT: @address_a 0 0 11 0 address_a 0 0 11 0 +// Retrieval info: CONNECT: @address_b 0 0 11 0 address_b 0 0 11 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock_a 0 0 0 0 +// Retrieval info: CONNECT: @clock1 0 0 0 0 clock_b 0 0 0 0 +// Retrieval info: CONNECT: @data_a 0 0 8 0 data_a 0 0 8 0 +// Retrieval info: CONNECT: @data_b 0 0 8 0 data_b 0 0 8 0 +// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren_a 0 0 0 0 +// Retrieval info: CONNECT: @wren_b 0 0 0 0 wren_b 0 0 0 0 +// Retrieval info: CONNECT: q_a 0 0 8 0 @q_a 0 0 8 0 +// Retrieval info: CONNECT: q_b 0 0 8 0 @q_b 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL data_io_ram.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL data_io_ram.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL data_io_ram.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL data_io_ram.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL data_io_ram_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL data_io_ram_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf diff --git a/cores/zxgate/zx/zx01/tape.v b/cores/zxgate/zx/zx01/tape.v new file mode 100644 index 0000000..833bbe2 --- /dev/null +++ b/cores/zxgate/zx/zx01/tape.v @@ -0,0 +1,212 @@ +// +// tape.v +// +// ZX81 tape implementation for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// This source file 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. +// +// This source file 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 this program. If not, see . +// + +module tape( + input sck, + input ss, + input sdi, + + input clk, // 500kHz + input play, // "press play on tape" + output reg tape_out +); + +// create clock to be used for signaltap +reg [7:0] tape_clk /* synthesis noprune */; +always @(posedge clk) + tape_clk <= tape_clk + 8'd1; + +// tape bit timing +// 0 bit = /\/\/\/\_________ (4* 150us H + 150us L + 1300us L) +// 1 bit = /\/\/\/\/\/\/\/\/\_____________ + +// 0 = idle, 1 = 1300us low, 2/4/6/../18 = 150us high, 3/5/7/../19 = 150us L +reg [4:0] pulse_state; + +// 150us = 75 cycles @ 500kHz +// 1300us = 650 cycles @ 500kHz +reg [9:0] pulse_cnt; // 10 bit = 1024 max range + +reg bit_done; + +// generate bit timing +always @(posedge clk) begin + bit_done <= 1'b0; + + if(pulse_cnt == 0) begin + // end of idle state, start new bit + if(pulse_state == 0) begin + if(bit_start) begin + tape_out <= 1'b1; + pulse_state <= bit?5'd19:5'd9; + pulse_cnt <= 10'd74; + end + end + + // end of 1300us seperator phase + else if(pulse_state == 1) begin + tape_out <= 1'b0; + pulse_state <= 5'd0; + pulse_cnt <= 10'd0; + bit_done <= 1'b1; + end + + // end of last high phase + else if(pulse_state == 2) begin + tape_out <= 1'b0; + pulse_state <= 5'd1; + pulse_cnt <= 10'd649; + end + + // end of normal pulse hi/lo phase + else if(pulse_state > 2) begin + // tape level is 1 when coming from state 4,6,8,... + tape_out <= !pulse_state[0]; + pulse_state <= pulse_state - 5'd1; + pulse_cnt <= 10'd74; + end + + end else + pulse_cnt <= pulse_cnt - 10'd1; +end + +// bring play signal into local clock domain and +// generate start signal from it +reg start; +reg playD, playD2; +always @(posedge clk) begin + start <= 1'b0; + playD <= play; + playD2 <= playD; + + if(playD && !playD2) + start <= 1'b1; +end + +// byte transmitter +wire bit = byte[bit_cnt]; + +// reg [7:0] byte = 8'h55 /* synthesis noprune */; +reg [2:0] bit_cnt; +reg byte_tx_running = 1'b0; +reg bit_in_progress; +reg bit_start; + +reg byte_done; + +always @(posedge clk) begin + bit_start <= 1'b0; + byte_done <= 1'b0; + + // start signal starts a new byte transmission + if(!byte_tx_running) begin + if(byte_start) begin + byte_tx_running <= 1'b1; + bit_in_progress <= 1'b0; + bit_cnt <= 3'd7; + end + end else begin + // byte transmission in progress + + if(!bit_in_progress) begin + // start new bit + bit_start <= 1'b1; + bit_in_progress <= 1'b1; + end else begin + // wait for bit transmission to finish + if(bit_done) begin + bit_in_progress <= 1'b0; + + if(bit_cnt != 0) + bit_cnt <= bit_cnt - 3'd1; + else begin + byte_tx_running <= 1'b0; + byte_done <= 1'b1; + end + end + end + end +end + +// byte tx engine +reg [15:0] byte_count; + +// 0=idle, 1=filename, 2=file +reg [1:0] byte_state = 2'd0; + +reg byte_start; + + +always @(posedge clk) begin + byte_start <= 1'b0; + + if(byte_state == 0) begin + // start transmission if user presses "play". don't do anything if + // there's no tape data in the buffer + if(start && (file_size != 0)) begin + byte_state <= 2'd1; + + // transmit the "file name" + byte_start <= 1'b1; + end + end else if(byte_state == 1) begin + if(byte_done) begin + byte_state <= 2'd2; + byte_start <= 1'b1; + byte_count <= 16'h0000; + end + + end else if(byte_state == 2) begin + if(byte_done) begin + if(byte_count != file_size - 16'd1) begin + byte_count <= byte_count + 16'd1; + byte_start <= 1'b1; + end else + byte_state <= 2'd0; + end + end +end + +wire [7:0] filename = { 1'b1, 7'h3f}; // 'Z' with end flag +wire [7:0] byte = (byte_state == 1)?filename:ram_data_out; +wire [7:0] ram_data_out; + +wire [15:0] file_size; + +// include the io controller connected ram +data_io data_io ( + .sck ( sck ), + .ss ( ss ), + .sdi ( sdi ), + + .downloading ( ), + .size ( file_size ), + + // ram interface + .clk ( clk ), + .we ( 1'b0 ), + .a ( byte_count[10:0] ), + .din ( 8'h00 ), + .dout ( ram_data_out ) +); + +endmodule \ No newline at end of file diff --git a/cores/zxgate/zx/zx01/user_io.v b/cores/zxgate/zx/zx01/user_io.v index f94e9d2..64a5aaf 100644 --- a/cores/zxgate/zx/zx01/user_io.v +++ b/cores/zxgate/zx/zx01/user_io.v @@ -1,4 +1,24 @@ -// MiST user_io +// +// user_io.v +// +// user_io for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// This source file 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. +// +// This source file 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 this program. If not, see . +// module user_io( input SPI_CLK, @@ -6,21 +26,27 @@ module user_io( output reg SPI_MISO, input SPI_MOSI, - input [7:0] CORE_TYPE, - output [5:0] JOY0, output [5:0] JOY1, output [1:0] BUTTONS, output [1:0] SWITCHES, + + output reg [7:0] status, input clk, output ps2_clk, output reg ps2_data ); +// config string, it is assumed that any core returning a string here +// also supports the OSD +// 0123456789abcdef +wire [127:0] name = "ZX01;P; "; + reg [6:0] sbuf; reg [7:0] cmd; -reg [4:0] cnt; +reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... +reg [5:0] byte_cnt; // counts bytes reg [5:0] joystick0; reg [5:0] joystick1; reg [3:0] but_sw; @@ -29,16 +55,28 @@ assign JOY0 = joystick0; assign JOY1 = joystick1; assign BUTTONS = but_sw[1:0]; assign SWITCHES = but_sw[3:2]; - + +// this variant of user_io is for 8 bit cores (type == a4) only +wire [7:0] core_type = 8'ha4; + // drive MISO only when transmitting core id always@(negedge SPI_CLK or posedge SPI_SS_IO) begin if(SPI_SS_IO == 1) begin SPI_MISO <= 1'bZ; end else begin - if(cnt < 8) begin - SPI_MISO <= CORE_TYPE[7-cnt]; + // first byte returned is always core type, further bytes are + // command dependent + if(byte_cnt == 0) begin + SPI_MISO <= core_type[~bit_cnt]; end else begin - SPI_MISO <= 1'bZ; + // reading config string + if(cmd == 8'h14) begin + // returning a byte from string + if(byte_cnt < 6'd17) + SPI_MISO <= name[{~(byte_cnt-6'd1),~bit_cnt}]; + else + SPI_MISO <= 1'b0; + end end end end @@ -56,7 +94,6 @@ reg ps2_parity; assign ps2_clk = clk || (ps2_tx_state == 0); - // ps2 transmitter // Takes a byte from the FIFO and sends it in a ps2 compliant serial format. reg ps2_r_inc; @@ -111,42 +148,42 @@ always@(posedge clk) begin end // SPI receiver -//reg ps2_w_inc; always@(posedge SPI_CLK or posedge SPI_SS_IO) begin -// ps2_w_inc <= 1'b0; -// if(ps2_w_inc) -// ps2_wptr <= ps2_wptr + 1; if(SPI_SS_IO == 1) begin - cnt <= 1'b0; + bit_cnt <= 3'd0; + byte_cnt <= 5'd0; end else begin sbuf[6:0] <= { sbuf[5:0], SPI_MOSI }; - // counter counts 0-7, 8-15, 8-15 ... - // 0-7 is command, 8-15 is payload - if(cnt != 15) cnt <= cnt + 4'd1; - else cnt <= 4'd8; + bit_cnt <= bit_cnt + 3'd1; + if(bit_cnt == 7) byte_cnt <= byte_cnt + 5'd1; // finished reading command byte - if(cnt == 7) - cmd <= { sbuf, SPI_MOSI}; + if(bit_cnt == 7) begin + if(byte_cnt == 0) + cmd <= { sbuf, SPI_MOSI}; - if(cnt == 15) begin - if(cmd == 1) - but_sw <= { sbuf[2:0], SPI_MOSI }; + if(byte_cnt != 0) begin + if(cmd == 8'h01) + but_sw <= { sbuf[2:0], SPI_MOSI }; - if(cmd == 2) - joystick0 <= { sbuf[4:0], SPI_MOSI }; + if(cmd == 8'h02) + joystick0 <= { sbuf[4:0], SPI_MOSI }; - if(cmd == 3) - joystick1 <= { sbuf[4:0], SPI_MOSI }; + if(cmd == 8'h03) + joystick1 <= { sbuf[4:0], SPI_MOSI }; - if(cmd == 5) begin - // store incoming keyboard bytes in - ps2_fifo[ps2_wptr] <= { sbuf, SPI_MOSI }; - ps2_wptr <= ps2_wptr + 1; - end + if(cmd == 8'h05) begin + // store incoming keyboard bytes in + ps2_fifo[ps2_wptr] <= { sbuf, SPI_MOSI }; + ps2_wptr <= ps2_wptr + 1; + end - end + if(cmd == 8'h15) begin + status <= { sbuf[4:0], SPI_MOSI }; + end + end + end end end diff --git a/cores/zxgate/zx/zx01/zx01.qsf b/cores/zxgate/zx/zx01/zx01.qsf index 2e0d750..748a3f4 100644 --- a/cores/zxgate/zx/zx01/zx01.qsf +++ b/cores/zxgate/zx/zx01/zx01.qsf @@ -287,8 +287,11 @@ set_global_assignment -name ENABLE_NCE_PIN OFF set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF set_global_assignment -name USE_CONFIGURATION_DEVICE OFF set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" -set_global_assignment -name ENABLE_SIGNALTAP ON +set_global_assignment -name ENABLE_SIGNALTAP OFF set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp +set_global_assignment -name VERILOG_FILE tape.v +set_global_assignment -name VERILOG_FILE data_io_ram.v +set_global_assignment -name VERILOG_FILE data_io.v set_global_assignment -name VERILOG_FILE osd.v set_global_assignment -name VERILOG_FILE user_io.v set_global_assignment -name QIP_FILE clock.qip diff --git a/cores/zxgate/zx/zx01/zx01_mist.v b/cores/zxgate/zx/zx01/zx01_mist.v index 98579d7..e0d53c7 100644 --- a/cores/zxgate/zx/zx01/zx01_mist.v +++ b/cores/zxgate/zx/zx01/zx01_mist.v @@ -1,8 +1,24 @@ - - -// Changes done to zx01/zx97 code: -// - removed open state from video in zx01.vhd -// - Use rom megafunction for zx81 rom (replaced rom81XXXX.vhd by single rom81.vhd) +// +// zx01_mist.v +// +// zx01/zx81 toplevel for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// This source file 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. +// +// This source file 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 this program. If not, see . +// module zx01_mist ( // clock inputsxque @@ -48,13 +64,13 @@ assign SDRAM_nCS = 1'b1; // disable ram // reset geenration reg [7:0] reset_cnt; always @(posedge clk) begin - if(!pll_locked) + if(!pll_locked || status[0]) reset_cnt <= 8'h0; else if(reset_cnt != 8'd255) reset_cnt <= reset_cnt + 8'd1; end -wire reset = reset_cnt != 8'd255; +wire reset = (reset_cnt != 8'd255); // pll to generate appropriate clock wire clk13; @@ -86,6 +102,8 @@ always @(posedge clk) wire ps2_clk; wire ps2_data; +wire [7:0] status; + user_io user_io( // the spi interface .SPI_CLK (SPI_SCK ), @@ -96,11 +114,17 @@ user_io user_io( .SWITCHES (switches ), .BUTTONS (buttons ), + // two joysticks supports + .JOY0 ( ), + .JOY1 ( ), + + // status byte (bit 0 = io controller reset) + .status ( status ), + + // ps2 keyboard interface .clk (clk_12k ), // should be 10-16kHz for ps2 clock .ps2_data (ps2_data ), - .ps2_clk (ps2_clk ), - - .CORE_TYPE (8'ha4 ) // 8 bit core id + .ps2_clk (ps2_clk ) ); // ----------------------- Quick'n dirty scan doubler --------------------------- @@ -244,6 +268,8 @@ always @(posedge clk13) begin sd_video <= line_buffer[{!sd_toggle, sd_col}]; end +wire tape_data; + zx01 zx01 ( .n_reset (~reset ), .clock (clk ), @@ -252,7 +278,7 @@ zx01 zx01 ( .v_inv (switches[1] ), .usa_uk (1'b0 ), .video (video ), - .tape_in (1'b0 ), + .tape_in (tape_data ), .tape_out (csync ), // ignore LCD interface @@ -262,4 +288,39 @@ zx01 zx01 ( .cp2 ( ) ); +// create 500kHz from 13 Mhz +reg [4:0] clk_cnt; +wire clk_500k = clk_cnt < 13; +always @(posedge clk13) begin + clk_cnt <= clk_cnt + 5'd1; + if(clk_cnt == 5'd25) + clk_cnt <= 5'd0; +end + +// tape transfers distort video, so we need a different kind +// of feedback +// we thus route type_data to led and to audio +assign LED = !tape_data; + +// use a pwm to reduce audio output volume +reg [7:0] aclk; +always @(posedge clk13) + aclk <= aclk + 8'd1; + +// limit volume to 1/8 => pwm < 32 +wire tape_audio = tape_data && (aclk < 32); +assign AUDIO_L = tape_audio; +assign AUDIO_R = tape_audio; + +tape tape ( + // spi interface to io controller + .sdi ( SPI_DI ), + .sck ( SPI_SCK ), + .ss ( SPI_SS2 ), + + .clk ( clk_500k ), + .play ( buttons[1] ), + .tape_out ( tape_data ) +); + endmodule