mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-05 07:34:41 +00:00
C16: import mist-modules, use common components
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "mist-modules"]
|
||||
path = mist-modules
|
||||
url = https://github.com/mist-devel/mist-modules.git
|
||||
@@ -41,7 +41,7 @@
|
||||
# ========================
|
||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:40:24 MAY 17, 2014"
|
||||
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name LAST_QUARTUS_VERSION "13.1 SP4.26"
|
||||
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
||||
set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
|
||||
set_global_assignment -name SMART_RECOMPILE ON
|
||||
@@ -348,11 +348,7 @@ set_global_assignment -name VHDL_FILE tap_fifo.vhd
|
||||
set_global_assignment -name VHDL_FILE c1530.vhd
|
||||
set_global_assignment -name VHDL_FILE gen_ram.vhd
|
||||
set_global_assignment -name VERILOG_FILE sigma_delta_dac.v
|
||||
set_global_assignment -name VERILOG_FILE data_io.v
|
||||
set_global_assignment -name VERILOG_FILE sdram.v
|
||||
set_global_assignment -name VERILOG_FILE osd.v
|
||||
set_global_assignment -name VERILOG_FILE scandoubler.v
|
||||
set_global_assignment -name VERILOG_FILE user_io.v
|
||||
set_global_assignment -name VERILOG_FILE ted.v
|
||||
set_global_assignment -name VERILOG_FILE mos8501.v
|
||||
set_global_assignment -name VERILOG_FILE mos6529.v
|
||||
@@ -363,6 +359,7 @@ set_global_assignment -name VERILOG_FILE c16_keymatrix.v
|
||||
set_global_assignment -name VERILOG_FILE c16.v
|
||||
set_global_assignment -name VERILOG_FILE ps2receiver.v
|
||||
set_global_assignment -name VERILOG_FILE basic_rom.v
|
||||
set_global_assignment -name QIP_FILE "../../mist-modules/mist.qip"
|
||||
set_global_assignment -name VHDL_FILE c1541/gcr_floppy.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541/spram.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541/gen_rom.vhd
|
||||
@@ -374,8 +371,6 @@ set_global_assignment -name VHDL_FILE t65/T65_Pack.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65_MCode.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65_ALU.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65.vhd
|
||||
set_global_assignment -name SIGNALTAP_FILE output_files/stp1.stp
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rgb2ypbpr.sv
|
||||
set_global_assignment -name QIP_FILE pll_c1541.qip
|
||||
set_global_assignment -name QIP_FILE pll_c16.qip
|
||||
set_global_assignment -name QIP_FILE rom_reconfig_pal.qip
|
||||
|
||||
@@ -77,14 +77,14 @@ parameter CONF_STR = {
|
||||
"F,ROM,Load Kernal;",
|
||||
"T6,Play/Stop tape;",
|
||||
"O7,Tape sound,Off,On;",
|
||||
"O2,Scanlines,Off,On;",
|
||||
"O12,Scanlines,Off,25%,50%,75%;",
|
||||
"O3,Joysticks,Normal,Swapped;",
|
||||
"O4,Memory,64k,16k;",
|
||||
"O89,SID,Off,6581,8580;",
|
||||
"T5,Reset;"
|
||||
};
|
||||
|
||||
parameter CONF_STR_LEN = 11+17+18+18+21+20+28+18+22+9;
|
||||
parameter CONF_STR_LEN = 11+17+18+18+21+30+28+18+22+9;
|
||||
|
||||
localparam ROM_MEM_START = 25'h10000;
|
||||
localparam TAP_MEM_START = 25'h20000;
|
||||
@@ -104,7 +104,8 @@ assign UART_TX = ~cass_motor;
|
||||
wire [31:0] status;
|
||||
wire tv15khz;
|
||||
wire ypbpr;
|
||||
wire scanlines = status[2];
|
||||
wire no_csync;
|
||||
wire [1:0] scanlines = status[2:1];
|
||||
wire joystick_swap = status[3];
|
||||
wire memory_16k = status[4];
|
||||
wire osd_reset = status[5];
|
||||
@@ -274,58 +275,54 @@ wire img_mounted;
|
||||
wire [8:0] sd_buff_addr;
|
||||
|
||||
// include user_io module for arm controller communication
|
||||
user_io #(.STRLEN(CONF_STR_LEN)) user_io (
|
||||
.conf_str ( CONF_STR ),
|
||||
user_io #(.STRLEN(CONF_STR_LEN)) user_io (
|
||||
.conf_str ( CONF_STR ),
|
||||
|
||||
.clk_sys ( clk28 ),
|
||||
.clk_sd ( clk32 ),
|
||||
.clk_sys ( clk28 ),
|
||||
.clk_sd ( clk32 ),
|
||||
|
||||
.SPI_CLK ( SPI_SCK ),
|
||||
.SPI_SS_IO ( CONF_DATA0 ),
|
||||
.SPI_MISO ( SPI_DO ),
|
||||
.SPI_MOSI ( SPI_DI ),
|
||||
.SPI_CLK ( SPI_SCK ),
|
||||
.SPI_SS_IO ( CONF_DATA0 ),
|
||||
.SPI_MISO ( SPI_DO ),
|
||||
.SPI_MOSI ( SPI_DI ),
|
||||
|
||||
.scandoubler_disable ( tv15khz ),
|
||||
.ypbpr ( ypbpr ),
|
||||
.buttons ( buttons ),
|
||||
.scandoubler_disable ( tv15khz ),
|
||||
.ypbpr ( ypbpr ),
|
||||
.no_csync ( no_csync ),
|
||||
.buttons ( buttons ),
|
||||
|
||||
.joystick_0 ( js0 ),
|
||||
.joystick_1 ( js1 ),
|
||||
.joystick_0 ( js0 ),
|
||||
.joystick_1 ( js1 ),
|
||||
|
||||
// ps2 interface
|
||||
.ps2_kbd_clk ( ps2_kbd_clk ),
|
||||
.ps2_kbd_data ( ps2_kbd_data ),
|
||||
.ps2_mouse_clk ( ps2_mouse_clk ),
|
||||
.ps2_mouse_data ( ps2_mouse_data ),
|
||||
// ps2 interface
|
||||
.ps2_kbd_clk ( ps2_kbd_clk ),
|
||||
.ps2_kbd_data ( ps2_kbd_data ),
|
||||
.ps2_mouse_clk ( ps2_mouse_clk ),
|
||||
.ps2_mouse_data ( ps2_mouse_data ),
|
||||
|
||||
.sd_lba ( sd_lba ),
|
||||
.sd_rd ( sd_rd ),
|
||||
.sd_wr ( sd_wr ),
|
||||
.sd_ack ( sd_ack ),
|
||||
.sd_ack_conf ( sd_ack_conf ),
|
||||
.sd_conf ( sd_conf ),
|
||||
.sd_sdhc ( sd_sdhc ),
|
||||
.sd_dout ( sd_dout ),
|
||||
.sd_dout_strobe ( sd_dout_strobe ),
|
||||
.sd_din ( sd_din ),
|
||||
.sd_din_strobe ( sd_din_strobe ),
|
||||
.sd_buff_addr ( sd_buff_addr),
|
||||
.img_mounted ( img_mounted ),
|
||||
.sd_lba ( sd_lba ),
|
||||
.sd_rd ( sd_rd ),
|
||||
.sd_wr ( sd_wr ),
|
||||
.sd_ack ( sd_ack ),
|
||||
.sd_ack_conf ( sd_ack_conf ),
|
||||
.sd_conf ( sd_conf ),
|
||||
.sd_sdhc ( sd_sdhc ),
|
||||
.sd_dout ( sd_dout ),
|
||||
.sd_dout_strobe ( sd_dout_strobe ),
|
||||
.sd_din ( sd_din ),
|
||||
.sd_din_strobe ( sd_din_strobe ),
|
||||
.sd_buff_addr ( sd_buff_addr ),
|
||||
.img_mounted ( img_mounted ),
|
||||
|
||||
.status ( status )
|
||||
.status ( status )
|
||||
);
|
||||
|
||||
wire sd_cs;
|
||||
wire sd_dat;
|
||||
wire sd_cmd;
|
||||
wire sd_clk;
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// ------------------------------ prg memory injection -----------------------------
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
wire ioctl_wr;
|
||||
wire [15:0] ioctl_addr;
|
||||
wire [24:0] ioctl_addr;
|
||||
wire [7:0] ioctl_data;
|
||||
wire [7:0] ioctl_index;
|
||||
wire ioctl_downloading;
|
||||
@@ -337,18 +334,18 @@ wire tap_download = ioctl_downloading && (ioctl_index == 8'h41);
|
||||
wire c16_wait = rom_download | prg_download;
|
||||
|
||||
data_io data_io (
|
||||
// SPI interface
|
||||
.sck ( SPI_SCK ),
|
||||
.ss ( SPI_SS2 ),
|
||||
.sdi ( SPI_DI ),
|
||||
|
||||
// ram interface
|
||||
.downloading ( ioctl_downloading ),
|
||||
.index ( ioctl_index ),
|
||||
.clk ( clk28 ),
|
||||
.wr ( ioctl_wr ),
|
||||
.a ( ioctl_addr ),
|
||||
.d ( ioctl_data )
|
||||
.clk_sys ( clk28 ),
|
||||
// SPI interface
|
||||
.SPI_SCK ( SPI_SCK ),
|
||||
.SPI_SS2 ( SPI_SS2 ),
|
||||
.SPI_DI ( SPI_DI ),
|
||||
|
||||
// ram interface
|
||||
.ioctl_download ( ioctl_downloading ),
|
||||
.ioctl_index ( ioctl_index ),
|
||||
.ioctl_wr ( ioctl_wr ),
|
||||
.ioctl_addr ( ioctl_addr ),
|
||||
.ioctl_dout ( ioctl_data )
|
||||
);
|
||||
|
||||
// magic zero page shadow registers to allow the injector to set the
|
||||
@@ -429,18 +426,18 @@ always @(posedge clk28) begin
|
||||
// data io has a byte for us
|
||||
if(ioctl_wr) begin
|
||||
if (prg_download) begin
|
||||
if(ioctl_addr == 16'h0000) ioctl_sdram_addr[7:0] <= ioctl_data;
|
||||
else if (ioctl_addr == 16'h0001) ioctl_sdram_addr[24:8] <= { 9'b0, ioctl_data };
|
||||
if(ioctl_addr == 0) ioctl_sdram_addr[7:0] <= ioctl_data;
|
||||
else if (ioctl_addr == 25'h1) ioctl_sdram_addr[24:8] <= { 9'b0, ioctl_data };
|
||||
else
|
||||
// io controller sent a new byte. Store it until it can be
|
||||
// saved in RAM
|
||||
ioctl_ram_wr <= 1'b1;
|
||||
end else if (tap_download) begin
|
||||
if(ioctl_addr == 16'h0000) ioctl_sdram_addr <= TAP_MEM_START;
|
||||
if(ioctl_addr == 0) ioctl_sdram_addr <= TAP_MEM_START;
|
||||
ioctl_ram_wr <= 1'b1;
|
||||
end else if (rom_download) begin
|
||||
if((ioctl_index == 8'h0 && ioctl_addr == 16'h4000) || (ioctl_index == 8'h3 && ioctl_addr == 16'h0000)) ioctl_sdram_addr <= ROM_MEM_START;
|
||||
if((ioctl_index == 8'h0 && ioctl_addr[15:14]) || ioctl_index == 8'h3) ioctl_ram_wr <= 1'b1;
|
||||
if((ioctl_index == 8'h0 && ioctl_addr == 25'h4000) || (ioctl_index == 8'h3 && ioctl_addr == 0)) ioctl_sdram_addr <= ROM_MEM_START;
|
||||
if((ioctl_index == 8'h0 && ioctl_addr[16:14] != 0) || ioctl_index == 8'h3) ioctl_ram_wr <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -521,90 +518,54 @@ c1530 c1530
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// ------------------------------ the on screen display ----------------------------
|
||||
// ---------------------------------- video output ---------------------------------
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
// in 15khz mode feed the c16 video directly into the OSD,
|
||||
// bypassing the scan doubler
|
||||
wire [5:0] osd_r_in = tv15khz?{c16_r, 2'b00}:video_r;
|
||||
wire [5:0] osd_g_in = tv15khz?{c16_g, 2'b00}:video_g;
|
||||
wire [5:0] osd_b_in = tv15khz?{c16_b, 2'b00}:video_b;
|
||||
wire osd_hs_in = tv15khz?c16_hs:video_hs;
|
||||
wire osd_vs_in = tv15khz?!c16_vs:video_vs;
|
||||
wire hs, vs;
|
||||
|
||||
wire osd_clk = tv15khz?clk7:clk14;
|
||||
mist_video #(.COLOR_DEPTH(4), .OSD_COLOR(3'd5), .SD_HCNT_WIDTH(10)) mist_video (
|
||||
.clk_sys ( clk28 ),
|
||||
|
||||
wire [5:0] red, green, blue;
|
||||
// OSD SPI interface
|
||||
.SPI_SCK ( SPI_SCK ),
|
||||
.SPI_SS3 ( SPI_SS3 ),
|
||||
.SPI_DI ( SPI_DI ),
|
||||
|
||||
// include the on screen display
|
||||
osd #(10'd11,10'd0,3'd5) osd (
|
||||
.clk_sys ( clk28 ),
|
||||
.ce_pix ( osd_clk ),
|
||||
// scanlines (00-none 01-25% 10-50% 11-75%)
|
||||
.scanlines ( scanlines ),
|
||||
|
||||
// spi for OSD
|
||||
.sdi ( SPI_DI ),
|
||||
.sck ( SPI_SCK ),
|
||||
.ss ( SPI_SS3 ),
|
||||
// non-scandoubled pixel clock divider 0 - clk_sys/4, 1 - clk_sys/2
|
||||
.ce_divider ( 1'b0 ),
|
||||
|
||||
.red_in ( osd_r_in ),
|
||||
.green_in ( osd_g_in ),
|
||||
.blue_in ( osd_b_in ),
|
||||
.hs_in ( osd_hs_in ),
|
||||
.vs_in ( osd_vs_in ),
|
||||
// 0 = HVSync 31KHz, 1 = CSync 15KHz
|
||||
.scandoubler_disable ( tv15khz ),
|
||||
// disable csync without scandoubler
|
||||
.no_csync ( no_csync ),
|
||||
// YPbPr always uses composite sync
|
||||
.ypbpr ( ypbpr ),
|
||||
// Rotate OSD [0] - rotate [1] - left or right
|
||||
.rotate ( 2'b00 ),
|
||||
// composite-like blending
|
||||
.blend ( 1'b0 ),
|
||||
|
||||
.red_out ( red ),
|
||||
.green_out ( green ),
|
||||
.blue_out ( blue )
|
||||
// video in
|
||||
.R ( c16_r ),
|
||||
.G ( c16_g ),
|
||||
.B ( c16_b ),
|
||||
|
||||
.HSync ( c16_hs ),
|
||||
.VSync ( ~c16_vs ),
|
||||
|
||||
// MiST video output signals
|
||||
.VGA_R ( VGA_R ),
|
||||
.VGA_G ( VGA_G ),
|
||||
.VGA_B ( VGA_B ),
|
||||
.VGA_VS ( vs ),
|
||||
.VGA_HS ( hs )
|
||||
);
|
||||
|
||||
wire [5:0] y, pb, pr;
|
||||
rgb2ypbpr rgb2ypbpr (
|
||||
.red ( red ),
|
||||
.green ( green ),
|
||||
.blue ( blue ),
|
||||
|
||||
.y ( y ),
|
||||
.pb ( pb ),
|
||||
.pr ( pr )
|
||||
);
|
||||
|
||||
assign VGA_R = ypbpr ? pr : red;
|
||||
assign VGA_G = ypbpr ? y : green;
|
||||
assign VGA_B = ypbpr ? pb : blue;
|
||||
|
||||
// in 15khz tv mode directly use the c16's composite sync. Otherwise the VGA
|
||||
// output is driven from the sync signals generated by the scan doubler. In
|
||||
// 15khz mode the VS signal is used as the RGB detect signal on the SCART
|
||||
// connector and thus needs to be driven to 1
|
||||
assign VGA_HS = tv15khz ? c16_cs:(ypbpr ? ~(video_hs ^ video_vs) : video_hs);
|
||||
assign VGA_VS = (tv15khz || ypbpr)?1'b1:video_vs;
|
||||
|
||||
wire video_hs, video_vs;
|
||||
wire [5:0] video_r;
|
||||
wire [5:0] video_g;
|
||||
wire [5:0] video_b;
|
||||
|
||||
scandoubler scandoubler (
|
||||
// system interface
|
||||
.clk_sys ( clk28 ),
|
||||
|
||||
// scanlines (00-none 01-25% 10-50% 11-75%)
|
||||
.scanlines ( scanlines?2'b10:2'b00 ),
|
||||
|
||||
// shifter video interface
|
||||
.hs_in ( c16_hs ),
|
||||
.vs_in ( !c16_vs ),
|
||||
.r_in ( c16_r ),
|
||||
.g_in ( c16_g ),
|
||||
.b_in ( c16_b ),
|
||||
|
||||
// output interface
|
||||
.hs_out ( video_hs ),
|
||||
.vs_out ( video_vs ),
|
||||
.r_out ( video_r ),
|
||||
.g_out ( video_g ),
|
||||
.b_out ( video_b )
|
||||
);
|
||||
// Use TED generated csync @15kHz
|
||||
assign VGA_HS = (~no_csync & tv15khz & ~ypbpr) ? c16_cs : hs;
|
||||
assign VGA_VS = (~no_csync & tv15khz & ~ypbpr) ? 1'b1 : vs;
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// ------------------------------------ c16 core -----------------------------------
|
||||
@@ -631,14 +592,14 @@ reg [13:0] rom_dl_addr;
|
||||
wire ioctl_rom_wr = rom_download && ioctl_wr;
|
||||
|
||||
always @(negedge clk28) begin
|
||||
reg last_ioctl_rom_wr;
|
||||
reg last_ioctl_rom_wr;
|
||||
last_ioctl_rom_wr <= ioctl_rom_wr;
|
||||
if(ioctl_rom_wr && !last_ioctl_rom_wr) begin
|
||||
rom_dl_data <= ioctl_data;
|
||||
rom_dl_addr <= ioctl_addr[13:0];
|
||||
c1541_dl_wr <= !ioctl_addr[15:14] && ioctl_index == 5'd0;
|
||||
kernal_dl_wr <= ioctl_addr[15:14] == 2'd1 || ioctl_index == 5'd3;
|
||||
basic_dl_wr <= ioctl_addr[15:14] == 2'd2 && ioctl_index == 5'd0;
|
||||
c1541_dl_wr <= ioctl_addr[16:14] == 3'd0 && ioctl_index == 8'h0;
|
||||
kernal_dl_wr <= ioctl_addr[16:14] == 3'd1 || ioctl_index == 8'h3;
|
||||
basic_dl_wr <= ioctl_addr[16:14] == 3'd2 && ioctl_index == 8'h0;
|
||||
end else
|
||||
{ kernal_dl_wr, basic_dl_wr, c1541_dl_wr } <= 0;
|
||||
end
|
||||
@@ -724,19 +685,6 @@ C16 #(.INTERNAL_ROM(0)) c16 (
|
||||
wire pll_locked = pll_c1541_locked && pll_c16_locked;
|
||||
wire ntsc = ~c16_pal;
|
||||
|
||||
// tv15hkz has quarter the pixel rate, so we need a 7mhz clock for the OSD
|
||||
reg clk7;
|
||||
reg clk14;
|
||||
|
||||
always @(posedge clk28) begin
|
||||
|
||||
reg [1:0] counter;
|
||||
|
||||
counter <= counter + 1'd1;
|
||||
clk7 <= !counter;
|
||||
clk14 <= !counter[0];
|
||||
end
|
||||
|
||||
// A PLL to derive the system clock from the MiSTs 27MHz
|
||||
wire pll_c1541_locked, clk32;
|
||||
pll_c1541 pll_c1541 (
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
//
|
||||
// data_io.v
|
||||
//
|
||||
// io controller writable ram for the MiST board
|
||||
// http://code.google.com/p/mist-board/
|
||||
//
|
||||
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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
|
||||
output reg [7:0] index, // menu index used to upload the file
|
||||
|
||||
// external ram interface
|
||||
input clk,
|
||||
output reg wr,
|
||||
output reg [15:0] a,
|
||||
output [7:0] d
|
||||
);
|
||||
|
||||
assign d = data;
|
||||
|
||||
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;
|
||||
localparam UIO_FILE_INDEX = 8'h55;
|
||||
localparam UIO_FILE_INFO = 8'h56;
|
||||
|
||||
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 <= 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;
|
||||
a <= addr;
|
||||
end
|
||||
|
||||
// expose file (menu) index
|
||||
if((cmd == UIO_FILE_INDEX) && (cnt == 15))
|
||||
index <= {sbuf[6:0], sdi};
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
reg rclkD, rclkD2;
|
||||
always@(posedge clk) begin
|
||||
// bring rclk from spi clock domain into c64 clock domain
|
||||
rclkD <= rclk;
|
||||
rclkD2 <= rclkD;
|
||||
wr <= 1'b0;
|
||||
|
||||
if(rclkD && !rclkD2)
|
||||
wr <= 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
208
cores/c16/osd.v
208
cores/c16/osd.v
@@ -1,208 +0,0 @@
|
||||
//
|
||||
// osd.v
|
||||
//
|
||||
// A simple OSD implementation. Can be hooked up between a cores
|
||||
// VGA output and the physical VGA pins
|
||||
//
|
||||
// Sinclair QL for the MiST
|
||||
// https://github.com/mist-devel
|
||||
//
|
||||
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
module osd (
|
||||
// OSDs pixel clock, should be synchronous to cores pixel clock to
|
||||
// avoid jitter.
|
||||
input clk_sys,
|
||||
input ce_pix,
|
||||
|
||||
// SPI interface
|
||||
input sck,
|
||||
input ss,
|
||||
input sdi,
|
||||
|
||||
// VGA signals coming from core
|
||||
input [5:0] red_in,
|
||||
input [5:0] green_in,
|
||||
input [5:0] blue_in,
|
||||
input hs_in,
|
||||
input vs_in,
|
||||
|
||||
// VGA signals going to video connector
|
||||
output [5:0] red_out,
|
||||
output [5:0] green_out,
|
||||
output [5:0] blue_out,
|
||||
output hs_out,
|
||||
output vs_out
|
||||
);
|
||||
|
||||
parameter OSD_X_OFFSET = 10'd0;
|
||||
parameter OSD_Y_OFFSET = 10'd0;
|
||||
parameter OSD_COLOR = 3'd0;
|
||||
|
||||
localparam OSD_WIDTH = 10'd256;
|
||||
localparam OSD_HEIGHT = 10'd128;
|
||||
|
||||
// *********************************************************************************
|
||||
// spi client
|
||||
// *********************************************************************************
|
||||
|
||||
// this core supports only the display related OSD commands
|
||||
// of the minimig
|
||||
reg [7:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
reg [4:0] cnt;
|
||||
reg [10:0] bcnt;
|
||||
reg osd_enable;
|
||||
|
||||
reg [7:0] osd_buffer [2047:0]; // the OSD buffer itself
|
||||
|
||||
// the OSD has its own SPI interface to the io controller
|
||||
always@(posedge sck, posedge ss) begin
|
||||
if(ss == 1'b1) begin
|
||||
cnt <= 5'd0;
|
||||
bcnt <= 11'd0;
|
||||
end else begin
|
||||
sbuf <= { sbuf[6:0], sdi};
|
||||
|
||||
// 0:7 is command, rest payload
|
||||
if(cnt < 15)
|
||||
cnt <= cnt + 4'd1;
|
||||
else
|
||||
cnt <= 4'd8;
|
||||
|
||||
if(cnt == 7) begin
|
||||
cmd <= {sbuf[6:0], sdi};
|
||||
|
||||
// lower three command bits are line address
|
||||
bcnt <= { sbuf[1:0], sdi, 8'h00};
|
||||
|
||||
// command 0x40: OSDCMDENABLE, OSDCMDDISABLE
|
||||
if(sbuf[6:3] == 4'b0100)
|
||||
osd_enable <= sdi;
|
||||
end
|
||||
|
||||
// command 0x20: OSDCMDWRITE
|
||||
if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin
|
||||
osd_buffer[bcnt] <= {sbuf[6:0], sdi};
|
||||
bcnt <= bcnt + 11'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// *********************************************************************************
|
||||
// video timing and sync polarity anaylsis
|
||||
// *********************************************************************************
|
||||
|
||||
// horizontal counter
|
||||
reg [9:0] h_cnt;
|
||||
reg [9:0] hs_low, hs_high;
|
||||
wire hs_pol = hs_high < hs_low;
|
||||
wire [9:0] h_dsp_width = hs_pol?hs_low:hs_high;
|
||||
wire [9:0] h_dsp_ctr = { 1'b0, h_dsp_width[9:1] };
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD;
|
||||
|
||||
if (ce_pix) begin
|
||||
hsD <= hs_in;
|
||||
|
||||
// falling edge of hs_in
|
||||
if(!hs_in && hsD) begin
|
||||
h_cnt <= 10'd0;
|
||||
hs_high <= h_cnt;
|
||||
end
|
||||
|
||||
// rising edge of hs_in
|
||||
else if(hs_in && !hsD) begin
|
||||
h_cnt <= 10'd0;
|
||||
hs_low <= h_cnt;
|
||||
end
|
||||
|
||||
else
|
||||
h_cnt <= h_cnt + 10'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// vertical counter
|
||||
reg [9:0] v_cnt;
|
||||
reg [9:0] vs_low, vs_high;
|
||||
wire vs_pol = vs_high < vs_low;
|
||||
wire [9:0] v_dsp_height = vs_pol?vs_low:vs_high;
|
||||
wire [9:0] v_dsp_ctr = { 1'b0, v_dsp_height[9:1] };
|
||||
wire doublescan = (v_dsp_height>350);
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD, vsD;
|
||||
|
||||
hsD <= hs_in;
|
||||
|
||||
if (~hsD & hs_in) begin
|
||||
vsD <= vs_in;
|
||||
|
||||
// falling edge of vs_in
|
||||
if(!vs_in && vsD) begin
|
||||
v_cnt <= 10'd0;
|
||||
vs_high <= v_cnt;
|
||||
end
|
||||
|
||||
// rising edge of vs_in
|
||||
else if(vs_in && !vsD) begin
|
||||
v_cnt <= 10'd0;
|
||||
vs_low <= v_cnt;
|
||||
end
|
||||
|
||||
else
|
||||
v_cnt <= v_cnt + 10'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// area in which OSD is being displayed
|
||||
wire [9:0] h_osd_start = h_dsp_ctr + OSD_X_OFFSET - (OSD_WIDTH >> 1);
|
||||
wire [9:0] h_osd_end = h_dsp_ctr + OSD_X_OFFSET + (OSD_WIDTH >> 1) - 1'd1;
|
||||
wire [9:0] v_osd_start = v_dsp_ctr + OSD_Y_OFFSET - (doublescan ? OSD_HEIGHT : OSD_HEIGHT >> 1);
|
||||
wire [9:0] v_osd_end = v_dsp_ctr + OSD_Y_OFFSET + (doublescan ? OSD_HEIGHT : OSD_HEIGHT >> 1) - 1'd1;
|
||||
|
||||
reg h_osd_active, v_osd_active;
|
||||
always @(posedge clk_sys) begin
|
||||
if(hs_in != hs_pol) begin
|
||||
if(h_cnt == h_osd_start) h_osd_active <= 1'b1;
|
||||
if(h_cnt == h_osd_end) h_osd_active <= 1'b0;
|
||||
end
|
||||
if(vs_in != vs_pol) begin
|
||||
if(v_cnt == v_osd_start) v_osd_active <= 1'b1;
|
||||
if(v_cnt == v_osd_end) v_osd_active <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
wire osd_de = osd_enable && h_osd_active && v_osd_active;
|
||||
|
||||
wire [9:0] osd_hcnt = h_cnt - h_osd_start + 7'd1; // one pixel offset for osd_byte register
|
||||
wire [9:0] osd_vcnt = v_cnt - v_osd_start;
|
||||
|
||||
reg [7:0] osd_byte;
|
||||
always @(posedge clk_sys) if(ce_pix) osd_byte <= osd_buffer[{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt[7:0]}];
|
||||
wire osd_pixel = osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]];
|
||||
|
||||
wire [2:0] osd_color = OSD_COLOR;
|
||||
assign red_out = !osd_de?red_in: {osd_pixel, osd_pixel, osd_color[2], red_in[5:3] };
|
||||
assign green_out = !osd_de?green_in:{osd_pixel, osd_pixel, osd_color[1], green_in[5:3]};
|
||||
assign blue_out = !osd_de?blue_in: {osd_pixel, osd_pixel, osd_color[0], blue_in[5:3] };
|
||||
|
||||
assign hs_out = hs_in;
|
||||
assign vs_out = vs_in;
|
||||
|
||||
endmodule
|
||||
@@ -1,55 +0,0 @@
|
||||
module rgb2ypbpr (
|
||||
input [5:0] red,
|
||||
input [5:0] green,
|
||||
input [5:0] blue,
|
||||
|
||||
output [5:0] y,
|
||||
output [5:0] pb,
|
||||
output [5:0] pr
|
||||
);
|
||||
|
||||
wire [5:0] yuv_full[225] = '{
|
||||
6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1,
|
||||
6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4,
|
||||
6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6,
|
||||
6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8,
|
||||
6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11,
|
||||
6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13,
|
||||
6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15,
|
||||
6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17,
|
||||
6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20,
|
||||
6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22,
|
||||
6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24,
|
||||
6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27,
|
||||
6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29,
|
||||
6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31,
|
||||
6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33,
|
||||
6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36,
|
||||
6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38,
|
||||
6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40,
|
||||
6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42,
|
||||
6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45,
|
||||
6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47,
|
||||
6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49,
|
||||
6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52,
|
||||
6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54,
|
||||
6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56,
|
||||
6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58,
|
||||
6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61,
|
||||
6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63,
|
||||
6'd63
|
||||
};
|
||||
|
||||
wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0});
|
||||
wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0});
|
||||
wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0});
|
||||
|
||||
wire [7:0] y_i = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8];
|
||||
wire [7:0] pb_i = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8];
|
||||
wire [7:0] pr_i = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8];
|
||||
|
||||
assign pr = yuv_full[pr_i - 8'd16];
|
||||
assign y = yuv_full[y_i - 8'd16];
|
||||
assign pb = yuv_full[pb_i - 8'd16];
|
||||
|
||||
endmodule
|
||||
@@ -1,177 +0,0 @@
|
||||
//
|
||||
// scandoubler.v
|
||||
//
|
||||
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
// TODO: Delay vsync one line
|
||||
|
||||
module scandoubler
|
||||
(
|
||||
// system interface
|
||||
input clk_sys,
|
||||
|
||||
// scanlines (00-none 01-25% 10-50% 11-75%)
|
||||
input [1:0] scanlines,
|
||||
|
||||
// shifter video interface
|
||||
input hs_in,
|
||||
input vs_in,
|
||||
input [3:0] r_in,
|
||||
input [3:0] g_in,
|
||||
input [3:0] b_in,
|
||||
|
||||
// output interface
|
||||
output reg hs_out,
|
||||
output reg vs_out,
|
||||
output reg [5:0] r_out,
|
||||
output reg [5:0] g_out,
|
||||
output reg [5:0] b_out
|
||||
);
|
||||
|
||||
|
||||
// try to detect changes in input signal and lock input clock gate
|
||||
// it
|
||||
reg last_hs_in;
|
||||
reg [1:0] i_div;
|
||||
wire ce_x1 = (i_div == 2'b01);
|
||||
wire ce_x2 = i_div[0];
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
if(last_hs_in != hs_in) begin
|
||||
i_div <= 2'b00;
|
||||
last_hs_in <= hs_in;
|
||||
end else begin
|
||||
i_div <= i_div + 2'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// --------------------- create output signals -----------------
|
||||
// latch everything once more to make it glitch free and apply scanline effect
|
||||
reg scanline;
|
||||
always @(posedge clk_sys) begin
|
||||
if(ce_x2) begin
|
||||
hs_out <= hs_sd;
|
||||
vs_out <= vs_in;
|
||||
|
||||
// reset scanlines at every new screen
|
||||
if(vs_out != vs_in) scanline <= 0;
|
||||
|
||||
// toggle scanlines at begin of every hsync
|
||||
if(hs_out && !hs_sd) scanline <= !scanline;
|
||||
|
||||
// if no scanlines or not a scanline
|
||||
if(!scanline || !scanlines) begin
|
||||
r_out <= { sd_out[11:8], 2'b00 };
|
||||
g_out <= { sd_out[7:4], 2'b00 };
|
||||
b_out <= { sd_out[3:0], 2'b00 };
|
||||
end else begin
|
||||
case(scanlines)
|
||||
1: begin // reduce 25% = 1/2 + 1/4
|
||||
r_out <= {1'b0, sd_out[11:8], 1'b0} + {2'b00, sd_out[11:8]};
|
||||
g_out <= {1'b0, sd_out[7:4], 1'b0} + {2'b00, sd_out[7:4] };
|
||||
b_out <= {1'b0, sd_out[3:0], 1'b0} + {2'b00, sd_out[3:0] };
|
||||
end
|
||||
|
||||
2: begin // reduce 50% = 1/2
|
||||
r_out <= {1'b0, sd_out[11:8], 1'b0};
|
||||
g_out <= {1'b0, sd_out[7:4], 1'b0};
|
||||
b_out <= {1'b0, sd_out[3:0], 1'b0};
|
||||
end
|
||||
|
||||
3: begin // reduce 75% = 1/4
|
||||
r_out <= {2'b00, sd_out[11:8]};
|
||||
g_out <= {2'b00, sd_out[7:4]};
|
||||
b_out <= {2'b00, sd_out[3:0]};
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// scan doubler output register
|
||||
reg [11:0] sd_out;
|
||||
|
||||
// ==================================================================
|
||||
// ======================== the line buffers ========================
|
||||
// ==================================================================
|
||||
|
||||
// 2 lines of 512 pixels 3*4 bit RGB
|
||||
(* ramstyle = "no_rw_check" *) reg [11:0] sd_buffer[1023:0];
|
||||
|
||||
// use alternating sd_buffers when storing/reading data
|
||||
reg line_toggle;
|
||||
|
||||
// total hsync time (in 16MHz cycles), hs_total reaches 1024
|
||||
reg [8:0] hs_max;
|
||||
reg [8:0] hs_rise;
|
||||
reg [8:0] hcnt;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD, vsD;
|
||||
|
||||
if(ce_x1) begin
|
||||
hsD <= hs_in;
|
||||
|
||||
// falling edge of hsync indicates start of line
|
||||
if(hsD && !hs_in) begin
|
||||
hs_max <= hcnt;
|
||||
hcnt <= 9'd0;
|
||||
end else begin
|
||||
hcnt <= hcnt + 9'd1;
|
||||
end
|
||||
|
||||
// save position of rising edge
|
||||
if(!hsD && hs_in) hs_rise <= hcnt;
|
||||
|
||||
vsD <= vs_in;
|
||||
if(vsD != vs_in) line_toggle <= 0;
|
||||
|
||||
// begin of incoming hsync
|
||||
if(hsD && !hs_in) line_toggle <= !line_toggle;
|
||||
|
||||
sd_buffer[{line_toggle, hcnt}] <= {r_in, g_in, b_in};
|
||||
end
|
||||
end
|
||||
|
||||
// ==================================================================
|
||||
// ==================== output timing generation ====================
|
||||
// ==================================================================
|
||||
|
||||
reg [8:0] sd_hcnt;
|
||||
reg hs_sd;
|
||||
|
||||
// timing generation runs 32 MHz (twice the input signal analysis speed)
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD;
|
||||
|
||||
if(ce_x2) begin
|
||||
hsD <= hs_in;
|
||||
|
||||
// output counter synchronous to input and at twice the rate
|
||||
sd_hcnt <= sd_hcnt + 9'd1;
|
||||
if(hsD && !hs_in) sd_hcnt <= hs_max;
|
||||
if(sd_hcnt == hs_max) sd_hcnt <= 0;
|
||||
|
||||
// replicate horizontal sync at twice the speed
|
||||
if(sd_hcnt == hs_max) hs_sd <= 0;
|
||||
if(sd_hcnt == hs_rise) hs_sd <= 1;
|
||||
|
||||
// read data from line sd_buffer
|
||||
sd_out <= sd_buffer[{~line_toggle, sd_hcnt}];
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
1186
cores/c16/stp1.stp
1186
cores/c16/stp1.stp
File diff suppressed because one or more lines are too long
@@ -1,522 +0,0 @@
|
||||
//
|
||||
// user_io.v
|
||||
//
|
||||
// user_io for the MiST board
|
||||
// http://code.google.com/p/mist-board/
|
||||
//
|
||||
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// parameter STRLEN and the actual length of conf_str have to match
|
||||
|
||||
module user_io #(parameter STRLEN=0, parameter PS2DIV=100) (
|
||||
input [(8*STRLEN)-1:0] conf_str,
|
||||
|
||||
input clk_sys, // clock for system-related messages (kbd, joy, etc...)
|
||||
input clk_sd, // clock for SD-card related messages
|
||||
|
||||
input SPI_CLK,
|
||||
input SPI_SS_IO,
|
||||
output reg SPI_MISO,
|
||||
input SPI_MOSI,
|
||||
|
||||
output reg [31:0] joystick_0,
|
||||
output reg [31:0] joystick_1,
|
||||
output reg [31:0] joystick_2,
|
||||
output reg [31:0] joystick_3,
|
||||
output reg [31:0] joystick_4,
|
||||
output reg [15:0] joystick_analog_0,
|
||||
output reg [15:0] joystick_analog_1,
|
||||
output [1:0] buttons,
|
||||
output [1:0] switches,
|
||||
output scandoubler_disable,
|
||||
output ypbpr,
|
||||
output reg [31:0] status,
|
||||
|
||||
// connection to sd card emulation
|
||||
input [31:0] sd_lba,
|
||||
input sd_rd,
|
||||
input sd_wr,
|
||||
output reg sd_ack,
|
||||
output reg sd_ack_conf,
|
||||
input sd_conf,
|
||||
input sd_sdhc,
|
||||
output reg [7:0] sd_dout, // valid on rising edge of sd_dout_strobe
|
||||
output reg sd_dout_strobe,
|
||||
input [7:0] sd_din,
|
||||
output reg sd_din_strobe,
|
||||
output reg [8:0] sd_buff_addr,
|
||||
|
||||
output reg img_mounted, //rising edge if a new image is mounted
|
||||
output reg [31:0] img_size, // size of image in bytes
|
||||
|
||||
// ps2 keyboard emulation
|
||||
output ps2_kbd_clk,
|
||||
output reg ps2_kbd_data,
|
||||
output ps2_mouse_clk,
|
||||
output reg ps2_mouse_data,
|
||||
|
||||
// serial com port
|
||||
input [7:0] serial_data,
|
||||
input serial_strobe
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
assign buttons = but_sw[1:0];
|
||||
assign switches = but_sw[3:2];
|
||||
assign scandoubler_disable = but_sw[4];
|
||||
assign ypbpr = but_sw[5];
|
||||
|
||||
// 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_CLK;
|
||||
|
||||
// ---------------- PS2 ---------------------
|
||||
// 8 byte fifos to store ps2 bytes
|
||||
localparam PS2_FIFO_BITS = 3;
|
||||
|
||||
reg ps2_clk;
|
||||
always @(negedge clk_sys) begin
|
||||
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 [(2**PS2_FIFO_BITS)-1:0];
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_kbd_wptr;
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_kbd_rptr;
|
||||
|
||||
// ps2 transmitter state machine
|
||||
reg [3:0] ps2_kbd_tx_state;
|
||||
reg [7:0] ps2_kbd_tx_byte;
|
||||
reg ps2_kbd_parity;
|
||||
|
||||
assign ps2_kbd_clk = ps2_clk || (ps2_kbd_tx_state == 0);
|
||||
|
||||
// ps2 transmitter
|
||||
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
|
||||
reg ps2_kbd_r_inc;
|
||||
always@(posedge clk_sys) begin
|
||||
reg ps2_clkD;
|
||||
|
||||
ps2_clkD <= ps2_clk;
|
||||
if (~ps2_clkD & ps2_clk) begin
|
||||
ps2_kbd_r_inc <= 1'b0;
|
||||
|
||||
if(ps2_kbd_r_inc)
|
||||
ps2_kbd_rptr <= ps2_kbd_rptr + 1'd1;
|
||||
|
||||
// transmitter is idle?
|
||||
if(ps2_kbd_tx_state == 0) begin
|
||||
// data in fifo present?
|
||||
if(ps2_kbd_wptr != ps2_kbd_rptr) begin
|
||||
// load tx register from fifo
|
||||
ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr];
|
||||
ps2_kbd_r_inc <= 1'b1;
|
||||
|
||||
// reset parity
|
||||
ps2_kbd_parity <= 1'b1;
|
||||
|
||||
// start transmitter
|
||||
ps2_kbd_tx_state <= 4'd1;
|
||||
|
||||
// put start bit on data line
|
||||
ps2_kbd_data <= 1'b0; // start bit is 0
|
||||
end
|
||||
end else begin
|
||||
|
||||
// transmission of 8 data bits
|
||||
if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin
|
||||
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;
|
||||
|
||||
// transmission of stop bit
|
||||
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 + 4'd1;
|
||||
else
|
||||
ps2_kbd_tx_state <= 4'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// mouse
|
||||
reg [7:0] ps2_mouse_fifo [(2**PS2_FIFO_BITS)-1:0];
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr;
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_mouse_rptr;
|
||||
|
||||
// ps2 transmitter state machine
|
||||
reg [3:0] ps2_mouse_tx_state;
|
||||
reg [7:0] ps2_mouse_tx_byte;
|
||||
reg ps2_mouse_parity;
|
||||
|
||||
assign ps2_mouse_clk = ps2_clk || (ps2_mouse_tx_state == 0);
|
||||
|
||||
// ps2 transmitter
|
||||
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
|
||||
reg ps2_mouse_r_inc;
|
||||
always@(posedge clk_sys) begin
|
||||
reg ps2_clkD;
|
||||
|
||||
ps2_clkD <= ps2_clk;
|
||||
if (~ps2_clkD & ps2_clk) begin
|
||||
ps2_mouse_r_inc <= 1'b0;
|
||||
|
||||
if(ps2_mouse_r_inc)
|
||||
ps2_mouse_rptr <= ps2_mouse_rptr + 1'd1;
|
||||
|
||||
// transmitter is idle?
|
||||
if(ps2_mouse_tx_state == 0) begin
|
||||
// data in fifo present?
|
||||
if(ps2_mouse_wptr != ps2_mouse_rptr) begin
|
||||
// load tx register from fifo
|
||||
ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr];
|
||||
ps2_mouse_r_inc <= 1'b1;
|
||||
|
||||
// reset parity
|
||||
ps2_mouse_parity <= 1'b1;
|
||||
|
||||
// start transmitter
|
||||
ps2_mouse_tx_state <= 4'd1;
|
||||
|
||||
// put start bit on data line
|
||||
ps2_mouse_data <= 1'b0; // start bit is 0
|
||||
end
|
||||
end else begin
|
||||
|
||||
// transmission of 8 data bits
|
||||
if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin
|
||||
ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits
|
||||
ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down
|
||||
if(ps2_mouse_tx_byte[0])
|
||||
ps2_mouse_parity <= !ps2_mouse_parity;
|
||||
end
|
||||
|
||||
// transmission of parity
|
||||
if(ps2_mouse_tx_state == 9)
|
||||
ps2_mouse_data <= ps2_mouse_parity;
|
||||
|
||||
// transmission of stop bit
|
||||
if(ps2_mouse_tx_state == 10)
|
||||
ps2_mouse_data <= 1'b1; // stop bit is 1
|
||||
|
||||
// advance state machine
|
||||
if(ps2_mouse_tx_state < 11)
|
||||
ps2_mouse_tx_state <= ps2_mouse_tx_state + 4'd1;
|
||||
else
|
||||
ps2_mouse_tx_state <= 4'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// fifo to receive serial data from core to be forwarded to io controller
|
||||
|
||||
// 16 byte fifo to store serial bytes
|
||||
localparam SERIAL_OUT_FIFO_BITS = 6;
|
||||
reg [7:0] serial_out_fifo [(2**SERIAL_OUT_FIFO_BITS)-1:0];
|
||||
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_wptr;
|
||||
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_rptr;
|
||||
|
||||
wire serial_out_data_available = serial_out_wptr != serial_out_rptr;
|
||||
wire [7:0] serial_out_byte = serial_out_fifo[serial_out_rptr] /* synthesis keep */;
|
||||
wire [7:0] serial_out_status = { 7'b1000000, serial_out_data_available};
|
||||
|
||||
// status[0] is reset signal from io controller and is thus used to flush
|
||||
// the fifo
|
||||
always @(posedge serial_strobe or posedge status[0]) begin
|
||||
if(status[0] == 1) begin
|
||||
serial_out_wptr <= 0;
|
||||
end else begin
|
||||
serial_out_fifo[serial_out_wptr] <= serial_data;
|
||||
serial_out_wptr <= serial_out_wptr + 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
always@(negedge spi_sck or posedge status[0]) begin
|
||||
if(status[0] == 1) begin
|
||||
serial_out_rptr <= 0;
|
||||
end else begin
|
||||
if((byte_cnt != 0) && (cmd == 8'h1b)) begin
|
||||
// read last bit -> 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 SPI_SS_IO) begin
|
||||
if(SPI_SS_IO == 1) begin
|
||||
bit_cnt <= 0;
|
||||
byte_cnt <= 0;
|
||||
end else begin
|
||||
if((bit_cnt == 7)&&(~&byte_cnt))
|
||||
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 SPI_SS_IO) begin
|
||||
if(SPI_SS_IO == 1) begin
|
||||
SPI_MISO <= 1'bZ;
|
||||
end else begin
|
||||
SPI_MISO <= spi_byte_out[~bit_cnt];
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
reg [31:0] sd_lba_r;
|
||||
|
||||
if(SPI_SS_IO == 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_MOSI};
|
||||
|
||||
spi_byte_out <= 0;
|
||||
case({(!byte_cnt) ? {sbuf, SPI_MOSI} : 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_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 = 0;
|
||||
reg spi_transfer_end_r = 1;
|
||||
reg [7:0] spi_byte_in;
|
||||
|
||||
// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
|
||||
if(SPI_SS_IO == 1) begin
|
||||
spi_transfer_end_r <= 1;
|
||||
end else begin
|
||||
spi_transfer_end_r <= 0;
|
||||
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], SPI_MOSI };
|
||||
|
||||
// finished reading a byte, prepare to transfer to clk_sys
|
||||
if(bit_cnt == 7) begin
|
||||
spi_byte_in <= { sbuf, SPI_MOSI};
|
||||
spi_receiver_strobe_r <= ~spi_receiver_strobe_r;
|
||||
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 spi_receiver_strobeD;
|
||||
reg spi_transfer_endD;
|
||||
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;
|
||||
|
||||
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)
|
||||
abyte_cnt <= abyte_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'h60: if (abyte_cnt < 5) joystick_0[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h61: if (abyte_cnt < 5) joystick_1[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h62: if (abyte_cnt < 5) joystick_2[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h63: if (abyte_cnt < 5) joystick_3[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h64: if (abyte_cnt < 5) joystick_4[(abyte_cnt-1)<<3 +:8] <= 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 index
|
||||
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<5) status[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 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 spi_receiver_strobeD;
|
||||
reg spi_transfer_endD;
|
||||
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;
|
||||
|
||||
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)
|
||||
abyte_cnt <= abyte_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_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_dout <= spi_byte_in;
|
||||
end
|
||||
|
||||
8'h1c: img_mounted <= 1;
|
||||
|
||||
// send image info
|
||||
8'h1d: if(abyte_cnt<5) img_size[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
1
mist-modules
Submodule
1
mist-modules
Submodule
Submodule mist-modules added at 232c10f768
Reference in New Issue
Block a user