1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-02 14:50:52 +00:00

Update MiST Modules

This commit is contained in:
Marcel
2024-07-13 20:45:08 +02:00
parent 29ff888969
commit c29cdda3a7
15 changed files with 1072 additions and 250 deletions

1
common/mist/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.bak

View File

@@ -21,7 +21,8 @@ module cofi (
output reg vs_out,
output reg [VIDEO_DEPTH-1:0] red_out,
output reg [VIDEO_DEPTH-1:0] green_out,
output reg [VIDEO_DEPTH-1:0] blue_out
output reg [VIDEO_DEPTH-1:0] blue_out,
output reg pix_ce_out
);
parameter VIDEO_DEPTH=8;
@@ -41,19 +42,23 @@ reg [VIDEO_DEPTH-1:0] green_last;
reg [VIDEO_DEPTH-1:0] blue_last;
wire ce = enable ? pix_ce : 1'b1;
always @(posedge clk) if (ce) begin
hblank_out <= hblank;
vblank_out <= vblank;
vs_out <= vs;
hs_out <= hs;
always @(posedge clk) begin
pix_ce_out <= 0;
if (ce) begin
hblank_out <= hblank;
vblank_out <= vblank;
vs_out <= vs;
hs_out <= hs;
pix_ce_out <= pix_ce;
red_last <= red;
blue_last <= blue;
green_last <= green;
red_last <= red;
blue_last <= blue;
green_last <= green;
red_out <= enable ? color_blend(red_last, red, hblank_out) : red;
blue_out <= enable ? color_blend(blue_last, blue, hblank_out) : blue;
green_out <= enable ? color_blend(green_last, green, hblank_out) : green;
red_out <= enable ? color_blend(red_last, red, hblank_out) : red;
blue_out <= enable ? color_blend(blue_last, blue, hblank_out) : blue;
green_out <= enable ? color_blend(green_last, green, hblank_out) : green;
end
end
endmodule

View File

@@ -43,8 +43,8 @@ module data_io
// Note: this is also set for user_io mounts.
// Valid when ioctl_download = 1 or when img_mounted strobe is active in user_io.
output reg ioctl_wr, // strobe indicating ioctl_dout valid
output reg [24:0] ioctl_addr,
output reg [7:0] ioctl_dout,
output reg [26:0] ioctl_addr,
output reg [((DOUT_16+1)*8)-1:0] ioctl_dout,
input [7:0] ioctl_din,
output reg [23:0] ioctl_fileext, // file extension
output reg [31:0] ioctl_filesize, // file size
@@ -56,7 +56,7 @@ module data_io
input hdd_dat_req,
output hdd_cdda_wr,
output hdd_status_wr,
output [2:0] hdd_addr = 0,
output [2:0] hdd_addr,
output hdd_wr,
output [15:0] hdd_data_out,
@@ -69,20 +69,21 @@ module data_io
output [1:0] hdd1_ena
);
parameter START_ADDR = 25'd0;
parameter ROM_DIRECT_UPLOAD = 0;
parameter USE_QSPI = 0;
parameter ENABLE_IDE = 0;
parameter START_ADDR = 27'd0;
parameter ROM_DIRECT_UPLOAD = 1'b0;
parameter USE_QSPI = 1'b0;
parameter ENABLE_IDE = 1'b0;
parameter DOUT_16 = 1'b0;
/////////////////////////////// DOWNLOADING ///////////////////////////////
reg [6:0] sbuf;
reg [7:0] data_w;
reg [7:0] data_w2 = 0;
reg [7:0] data_w3 = 0;
reg [3:0] cnt;
reg [7:0] cmd;
reg [6:0] bytecnt;
reg [14:0] sbuf;
reg [15:0] data_w;
reg [7:0] data_w2 = 0;
reg [15:0] data_w3 = 0;
reg [3:0] cnt;
reg [7:0] cmd;
reg [6:0] bytecnt;
reg rclk = 0;
reg rclk2 = 0;
@@ -118,12 +119,14 @@ wire [7:0] cmdcode = { 4'h0, hdd_dat_req, hdd_cmd_req, 2'b00 };
always@(negedge SPI_SCK or posedge SPI_SS2) begin : SPI_TRANSMITTER
reg [7:0] dout_r;
reg oe;
if(SPI_SS2) begin
oe <= 0;
reg_do <= 1'bZ;
end else begin
if (cnt == 0) dout_r <= cmdcode;
if (cnt == 15) begin
oe <= 1;
case(cmd)
CMD_IDE_REGS_RD,
CMD_IDE_DATA_RD:
@@ -135,12 +138,11 @@ always@(negedge SPI_SCK or posedge SPI_SS2) begin : SPI_TRANSMITTER
DIO_FILE_RX_DAT:
dout_r <= ioctl_din;
default:
dout_r <= 0;
default: oe <= 0;
endcase
end
reg_do <= dout_r[~cnt[2:0]];
reg_do <= (!cnt[3] & ENABLE_IDE) ? cmdcode[~cnt[2:0]] : oe ? dout_r[~cnt[2:0]] : 1'bZ;
end
end
@@ -150,16 +152,14 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
bytecnt <= 0;
cnt <= 0;
end else begin
// don't shift in last bit. It is evaluated directly
// when writing to ram
if(cnt != 15) sbuf <= { sbuf[5:0], SPI_DI};
sbuf <= { sbuf[13:0], SPI_DI};
// count 0-7 8-15 8-15 ...
if(cnt != 15) cnt <= cnt + 1'd1;
else cnt <= 8;
// finished command byte
if(cnt == 7) cmd <= {sbuf, SPI_DI};
if(cnt == 7) cmd <= {sbuf[6:0], SPI_DI};
if(cnt == 15) begin
if (~&bytecnt) bytecnt <= bytecnt + 1'd1;
@@ -167,7 +167,7 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
case (cmd)
// prepare/end transmission
DIO_FILE_TX: begin
DIO_FILE_TX:
// prepare
if(SPI_DI) begin
addr_reset <= ~addr_reset;
@@ -175,9 +175,8 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
end else begin
downloading_reg <= 0;
end
end
DIO_FILE_RX: begin
DIO_FILE_RX:
// prepare
if(SPI_DI) begin
addr_reset <= ~addr_reset;
@@ -185,31 +184,32 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
end else begin
uploading_reg <= 0;
end
end
// command 0x57: DIO_FILE_RX_DAT
// command 0x54: DIO_FILE_TX_DAT
DIO_FILE_RX_DAT,
DIO_FILE_TX_DAT: begin
data_w <= {sbuf, SPI_DI};
DIO_FILE_RX_DAT:
rclk <= ~rclk;
end
DIO_FILE_TX_DAT:
if (bytecnt[0] | !DOUT_16) begin
data_w <= {sbuf, SPI_DI};
rclk <= ~rclk;
end
// expose file (menu) index
DIO_FILE_INDEX: ioctl_index <= {sbuf, SPI_DI};
DIO_FILE_INDEX: ioctl_index <= {sbuf[6:0], SPI_DI};
// receiving FAT directory entry (mist-firmware/fat.h - DIRENTRY)
DIO_FILE_INFO: begin
DIO_FILE_INFO:
case (bytecnt)
8'h08: ioctl_fileext[23:16] <= {sbuf, SPI_DI};
8'h09: ioctl_fileext[15: 8] <= {sbuf, SPI_DI};
8'h0A: ioctl_fileext[ 7: 0] <= {sbuf, SPI_DI};
8'h1C: ioctl_filesize[ 7: 0] <= {sbuf, SPI_DI};
8'h1D: ioctl_filesize[15: 8] <= {sbuf, SPI_DI};
8'h1E: ioctl_filesize[23:16] <= {sbuf, SPI_DI};
8'h1F: ioctl_filesize[31:24] <= {sbuf, SPI_DI};
8'h08: ioctl_fileext[23:16] <= {sbuf[6:0], SPI_DI};
8'h09: ioctl_fileext[15: 8] <= {sbuf[6:0], SPI_DI};
8'h0A: ioctl_fileext[ 7: 0] <= {sbuf[6:0], SPI_DI};
8'h1C: ioctl_filesize[ 7: 0] <= {sbuf[6:0], SPI_DI};
8'h1D: ioctl_filesize[15: 8] <= {sbuf[6:0], SPI_DI};
8'h1E: ioctl_filesize[23:16] <= {sbuf[6:0], SPI_DI};
8'h1F: ioctl_filesize[31:24] <= {sbuf[6:0], SPI_DI};
endcase
end
endcase
end
end
@@ -255,31 +255,35 @@ endgenerate
generate if (USE_QSPI) begin
always@(negedge QSCK, posedge QCSn) begin : QSPI_RECEIVER
reg nibble_lo;
reg [1:0] nibble;
reg cmd_got;
reg cmd_write;
if (QCSn) begin
cmd_got <= 0;
cmd_write <= 0;
nibble_lo <= 0;
nibble <= 0;
end else begin
nibble_lo <= ~nibble_lo;
if (nibble_lo) begin
data_w3[3:0] <= QDAT;
if (!cmd_got) begin
nibble <= nibble + 1'd1;
data_w3 <= {data_w3[11:0], QDAT};
if (!cmd_got) begin
// first byte is the command
if (nibble[0]) begin
nibble <= 0;
cmd_got <= 1;
if ({data_w3[7:4], QDAT} == QSPI_WRITE) cmd_write <= 1;
end else begin
if (cmd_write) rclk3 <= ~rclk3;
if ({data_w3[3:0], QDAT} == QSPI_WRITE) cmd_write <= 1;
end
end else
data_w3[7:4] <= QDAT;
end else if ((DOUT_16 && &nibble) || (!DOUT_16 & nibble[0])) begin
if (cmd_write) rclk3 <= ~rclk3;
end
end
end
end
endgenerate
reg wr_int, wr_int_direct, wr_int_qspi, rd_int;
wire [15:0] ioctl_dout_next = wr_int ? data_w : data_w3;
always@(posedge clk_sys) begin : DATA_OUT
// synchronisers
reg rclkD, rclkD2;
@@ -287,9 +291,9 @@ always@(posedge clk_sys) begin : DATA_OUT
reg rclk3D, rclk3D2;
reg addr_resetD, addr_resetD2;
reg wr_int, wr_int_direct, wr_int_qspi, rd_int;
reg [24:0] addr;
reg [26:0] addr;
reg [31:0] filepos;
reg [7:0] tmp;
// bring flags from spi clock domain into core clock domain
{ rclkD, rclkD2 } <= { rclk, rclkD };
@@ -315,11 +319,31 @@ always@(posedge clk_sys) begin : DATA_OUT
wr_int <= 0;
wr_int_direct <= 0;
wr_int_qspi <= 0;
if (wr_int || wr_int_direct || wr_int_qspi) begin
ioctl_dout <= wr_int ? data_w : wr_int_direct ? data_w2 : data_w3;
ioctl_wr <= 1;
if (wr_int_direct) begin
if (DOUT_16) begin
if (addr[0]) begin
ioctl_dout <= {data_w2, tmp};
ioctl_wr <= 1;
ioctl_addr <= {addr[26:1], 1'b0};
end else
tmp <= data_w2;
end else begin
ioctl_dout <= data_w2;
ioctl_wr <= 1;
ioctl_addr <= addr;
end
addr <= addr + 1'd1;
end
if (wr_int | wr_int_qspi) begin
ioctl_wr <= 1;
ioctl_addr <= addr;
if (DOUT_16) begin
ioctl_dout <= {ioctl_dout_next[7:0], ioctl_dout_next[15:8]};
addr <= addr + 2'd2;
end else begin
ioctl_dout <= ioctl_dout_next[7:0];
addr <= addr + 1'd1;
end
end
if (rd_int) begin
ioctl_addr <= ioctl_addr + 1'd1;
@@ -383,7 +407,7 @@ reg rclk_ide_regs_wr = 0;
reg rclk_ide_wr = 0;
reg rclk_ide_rd = 0;
reg rclk_cdda_wr = 0;
reg [7:0] data_ide;
reg [15:0] data_ide;
always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER_IDE
if(SPI_SS2) begin
@@ -403,13 +427,13 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER_IDE
CMD_IDE_STATUS_WR:
if (bytecnt == 0) begin
data_ide <= {sbuf, SPI_DI};
data_ide[7:0] <= {sbuf[6:0], SPI_DI};
rclk_ide_stat <= ~rclk_ide_stat;
end
CMD_IDE_REGS_WR:
if (bytecnt >= 8 && bytecnt <= 18 && !bytecnt[0]) begin
data_ide <= {sbuf, SPI_DI};
data_ide[7:0] <= {sbuf[6:0], SPI_DI};
rclk_ide_regs_wr <= ~rclk_ide_regs_wr;
end
@@ -419,13 +443,13 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER_IDE
end
CMD_IDE_DATA_WR:
if (bytecnt > 4) begin
if (bytecnt > 4 & !bytecnt[0]) begin
data_ide <= {sbuf, SPI_DI};
rclk_ide_wr <= ~rclk_ide_wr;
end
CMD_IDE_CDDA_WR:
if (bytecnt > 4) begin
if (bytecnt > 4 & !bytecnt[0]) begin
data_ide <= {sbuf, SPI_DI};
rclk_cdda_wr <= ~rclk_cdda_wr;
end
@@ -483,7 +507,7 @@ always@(posedge hdd_clk) begin : IDE_OUT
if (rclk_ide_statD ^ rclk_ide_statD2) begin
int_hdd_status_wr <= 1;
int_hdd_data_out <= {8'h00, data_ide};
int_hdd_data_out <= {8'h00, data_ide[7:0]};
end
if (rclk_ide_rdD ^ rclk_ide_rdD2) begin
loword <= ~loword;
@@ -491,23 +515,15 @@ always@(posedge hdd_clk) begin : IDE_OUT
int_hdd_data_rd <= 1;
end
if (rclk_ide_wrD ^ rclk_ide_wrD2) begin
loword <= ~loword;
if (!loword)
int_hdd_data_out[15:8] <= data_ide;
else begin
int_hdd_data_wr <= 1;
int_hdd_data_out[7:0] <= data_ide;
end
int_hdd_data_out <= data_ide;
int_hdd_data_wr <= 1;
end
if (rclk_cdda_wrD ^ rclk_cdda_wrD2) begin
loword <= ~loword;
if (!loword)
int_hdd_data_out[15:8] <= data_ide;
else begin
int_hdd_cdda_wr <= 1;
int_hdd_data_out[7:0] <= data_ide;
end
int_hdd_data_out <= data_ide;
int_hdd_cdda_wr <= 1;
end
if (rclk2D ^ rclk2D2 && !downloading_reg) begin
loword <= ~loword;
if (!loword)
@@ -519,7 +535,7 @@ always@(posedge hdd_clk) begin : IDE_OUT
end
if (rclk_ide_regs_wrD ^ rclk_ide_regs_wrD2) begin
int_hdd_wr <= 1;
int_hdd_data_out <= {8'h00, data_ide};
int_hdd_data_out <= {8'h00, data_ide[7:0]};
int_hdd_addr <= int_hdd_addr + 1'd1;
end
if (rclk_ide_regs_rdD ^ rclk_ide_regs_rdD2) begin

111
common/mist/i2c_master.v Normal file
View File

@@ -0,0 +1,111 @@
// taken and tweaked from MiSTer sys/
module i2c_master
(
input CLK,
input I2C_START,
input I2C_READ,
input [6:0] I2C_ADDR,
input [7:0] I2C_SUBADDR,
input [7:0] I2C_WDATA,
output [7:0] I2C_RDATA,
output reg I2C_END = 1,
output reg I2C_ACK = 0,
//I2C bus
inout I2C_SCL,
inout I2C_SDA
);
// Clock Setting
parameter CLK_Freq = 50_000_000; // 50 MHz
parameter I2C_Freq = 400_000; // 400 KHz
localparam I2C_FreqX2 = I2C_Freq*2;
reg I2C_CLOCK;
reg [31:0] cnt;
wire [31:0] cnt_next = cnt + I2C_FreqX2;
always @(posedge CLK) begin
cnt <= cnt_next;
if(cnt_next >= CLK_Freq) begin
cnt <= cnt_next - CLK_Freq;
I2C_CLOCK <= ~I2C_CLOCK;
end
end
reg SCLK;
reg [11:0] SDO;
reg [0:7] rdata;
reg [6:0] SD_COUNTER;
reg [0:42] SD;
assign I2C_SCL = (SCLK | I2C_CLOCK) ? 1'bZ : 1'b0;
assign I2C_SDA = ((CLK_Freq/I2C_Freq) > 250 ? SDO[11] : ((CLK_Freq/I2C_Freq) > 20 ? SDO[7] : SDO[3])) ? 1'bZ : 1'b0;
initial begin
SD_COUNTER = 'b1111111;
SD = {40'hFFFFFFFFFF, 3'b111};
SCLK = 1;
SDO = 12'hFFF;
end
assign I2C_RDATA = rdata;
always @(posedge CLK) begin
reg old_clk;
reg old_st;
reg rd;
reg sda_in;
old_clk <= I2C_CLOCK;
old_st <= I2C_START;
sda_in <= I2C_SDA;
// delay to make sure SDA changed while SCL is stabilized at low
if(old_clk && ~I2C_CLOCK && ~SD_COUNTER[6]) SDO[0] <= SD[SD_COUNTER[5:0]];
SDO[11:1] <= SDO[10:0];
if(~old_st && I2C_START) begin
SCLK <= 1;
SDO <= 12'hFFF;
I2C_ACK <= 0;
I2C_END <= 0;
rd <= I2C_READ;
if(I2C_READ) SD[0:42] <= {2'b10, I2C_ADDR, 1'b0, 1'b1, I2C_SUBADDR, 3'b110, I2C_ADDR, 1'b1, 1'b1, 8'b11111111, 4'b1011};
else SD[0:31] <= {2'b10, I2C_ADDR, 1'b0, 1'b1, I2C_SUBADDR, 1'b1, I2C_WDATA, 4'b1011};
SD_COUNTER <= 0;
end else begin
if(~old_clk && I2C_CLOCK && ~SD_COUNTER[6]) begin
SD_COUNTER <= SD_COUNTER + 6'd1;
case(SD_COUNTER)
01: SCLK <= 0;
10: I2C_ACK <= ~sda_in;
19: I2C_ACK <= ~sda_in;
20: if (rd) SCLK <= 1; // repeated start
21: if (rd) SCLK <= 0;
28: if (~rd) I2C_ACK <= ~sda_in;
29: if (~rd) SCLK <= 1;
30: if (rd) I2C_ACK <= ~sda_in;
32: if (~rd) begin
I2C_END <= 1;
SD_COUNTER <= 64;
end
40: SCLK <= 1;
42: begin
I2C_END <= 1;
SD_COUNTER <= 64;
end
64: SCLK <= 1;
default: ;
endcase
if(SD_COUNTER >= 31 && SD_COUNTER <= 38) rdata[SD_COUNTER[5:0]-31] <= sda_in;
end
end
end
endmodule

72
common/mist/i2s.v Normal file
View File

@@ -0,0 +1,72 @@
// taken and tweaked from MiSTer sys/
module i2s
(
input reset,
input clk,
input [31:0] clk_rate,
output reg sclk,
output reg lrclk,
output reg sdata,
input [AUDIO_DW-1:0] left_chan,
input [AUDIO_DW-1:0] right_chan
);
// Clock Setting
parameter I2S_Freq = 48_000; // 48 KHz
parameter AUDIO_DW = 16;
localparam I2S_FreqX2 = I2S_Freq*2*AUDIO_DW*2;
reg [31:0] cnt;
wire [31:0] cnt_next = cnt + I2S_FreqX2;
reg ce;
always @(posedge clk) begin
ce <= 0;
cnt <= cnt_next;
if(cnt_next >= clk_rate) begin
cnt <= cnt_next - clk_rate;
ce <= 1;
end
end
always @(posedge clk) begin
reg [4:0] bit_cnt = 1;
reg [AUDIO_DW-1:0] left;
reg [AUDIO_DW-1:0] right;
if (reset) begin
bit_cnt <= 1;
lrclk <= 1;
sclk <= 1;
sdata <= 1;
sclk <= 1;
end
else begin
if(ce) begin
sclk <= ~sclk;
if(sclk) begin
if(bit_cnt == AUDIO_DW) begin
bit_cnt <= 1;
lrclk <= ~lrclk;
if(lrclk) begin
left <= left_chan;
right <= right_chan;
end
end
else begin
bit_cnt <= bit_cnt + 1'd1;
end
sdata <= lrclk ? right[AUDIO_DW - bit_cnt] : left[AUDIO_DW - bit_cnt];
end
end
end
end
endmodule

View File

@@ -1,14 +1,18 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) mist.vhd]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) user_io.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) data_io.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mist_video.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_inputs.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sd_card.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ide.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ide_fifo.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) cdda_fifo.v]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) dac.vhd]
set_global_assignment -library mist -name VHDL_FILE [file join $::quartus(qip_path) mist.vhd]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) user_io.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) data_io.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) mist_video.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) osd.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) arcade_inputs.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) video_cleaner.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v]
set_global_assignment -library mist -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) sd_card.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) ide.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) ide_fifo.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) cdda_fifo.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) i2c_master.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) i2s.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) spdif.v]
set_global_assignment -library mist -name VHDL_FILE [file join $::quartus(qip_path) dac.vhd]

View File

@@ -78,20 +78,33 @@ port (
mouse_z : out signed(3 downto 0);
mouse_flags : out std_logic_vector(7 downto 0); -- YOvfl, XOvfl, dy8, dx8, 1, mbtn, rbtn, lbtn
mouse_strobe : out std_logic;
mouse_idx : out std_logic
mouse_idx : out std_logic;
i2c_start : out std_logic;
i2c_read : out std_logic;
i2c_addr : out std_logic_vector(6 downto 0);
i2c_subaddr : out std_logic_vector(7 downto 0);
i2c_dout : out std_logic_vector(7 downto 0);
i2c_din : in std_logic_vector(7 downto 0) := (others => '0');
i2c_end : in std_logic := '0';
i2c_ack : in std_logic := '0'
);
end component user_io;
component mist_video
generic (
OSD_COLOR : std_logic_vector(2 downto 0) := "110";
OSD_X_OFFSET : std_logic_vector(9 downto 0) := (others => '0');
OSD_Y_OFFSET : std_logic_vector(9 downto 0) := (others => '0');
SD_HCNT_WIDTH: integer := 9;
COLOR_DEPTH : integer := 6;
OSD_AUTO_CE : boolean := true;
SYNC_AND : boolean := false;
USE_BLANKS : boolean := false
OSD_COLOR : std_logic_vector(2 downto 0) := "110";
OSD_X_OFFSET : std_logic_vector(9 downto 0) := (others => '0');
OSD_Y_OFFSET : std_logic_vector(9 downto 0) := (others => '0');
SD_HCNT_WIDTH : integer := 9;
COLOR_DEPTH : integer := 6;
OSD_AUTO_CE : boolean := true;
SYNC_AND : boolean := false;
USE_BLANKS : boolean := false;
SD_HSCNT_WIDTH : integer := 12;
OUT_COLOR_DEPTH : integer := 6;
BIG_OSD : boolean := false;
VIDEO_CLEANER : boolean := false
);
port (
clk_sys : in std_logic;
@@ -118,10 +131,37 @@ port (
VGA_HS : out std_logic;
VGA_VS : out std_logic;
VGA_R : out std_logic_vector(5 downto 0);
VGA_G : out std_logic_vector(5 downto 0);
VGA_B : out std_logic_vector(5 downto 0)
VGA_HB : out std_logic;
VGA_VB : out std_logic;
VGA_DE : out std_logic;
VGA_R : out std_logic_vector(OUT_COLOR_DEPTH-1 downto 0);
VGA_G : out std_logic_vector(OUT_COLOR_DEPTH-1 downto 0);
VGA_B : out std_logic_vector(OUT_COLOR_DEPTH-1 downto 0)
);
end component mist_video;
component i2c_master
generic (
CLK_Freq : integer := 50000000;
I2C_Freq : integer := 400000
);
port (
CLK : in std_logic;
I2C_START : in std_logic;
I2C_READ : in std_logic;
I2C_ADDR : in std_logic_vector(6 downto 0);
I2C_SUBADDR : in std_logic_vector(7 downto 0);
I2C_WDATA : in std_logic_vector(7 downto 0);
I2C_RDATA : out std_logic_vector(7 downto 0);
I2C_END : out std_logic;
I2C_ACK : out std_logic;
-- I2C bus
I2C_SCL : inout std_logic;
I2C_SDA : inout std_logic
);
end component i2c_master;
end package;

View File

@@ -1,7 +1,8 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) mist.vhd]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) user_io.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mist_video.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv]
set_global_assignment -library mist -name VHDL_FILE [file join $::quartus(qip_path) mist.vhd]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) user_io.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) mist_video.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) osd.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) video_cleaner.v]
set_global_assignment -library mist -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v]
set_global_assignment -library mist -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv]

View File

@@ -41,25 +41,32 @@ module mist_video
input VSync,
// MiST video output signals
output reg [5:0] VGA_R,
output reg [5:0] VGA_G,
output reg [5:0] VGA_B,
output reg [OUT_COLOR_DEPTH-1:0] VGA_R,
output reg [OUT_COLOR_DEPTH-1:0] VGA_G,
output reg [OUT_COLOR_DEPTH-1:0] VGA_B,
output reg VGA_VS,
output reg VGA_HS
output reg VGA_HS,
output reg VGA_HB,
output reg VGA_VB,
output reg VGA_DE
);
parameter OSD_COLOR = 3'd4;
parameter OSD_X_OFFSET = 10'd0;
parameter OSD_Y_OFFSET = 10'd0;
parameter SD_HCNT_WIDTH = 9;
parameter COLOR_DEPTH = 6; // 1-6
parameter COLOR_DEPTH = 6; // 1-8
parameter OSD_AUTO_CE = 1'b1;
parameter SYNC_AND = 1'b0; // 0 - XOR, 1 - AND
parameter USE_BLANKS = 1'b0; // Honor H/VBlank signals?
parameter SYNC_AND = 1'b0; // 0 - XOR, 1 - AND
parameter USE_BLANKS = 1'b0; // Honor H/VBlank signals?
parameter SD_HSCNT_WIDTH = 12;
parameter OUT_COLOR_DEPTH = 6; // 1-8
parameter BIG_OSD = 1'b0; // 16 line OSD
parameter VIDEO_CLEANER = 1'b0; // Align VSync/VBlank to HSync/HBlank edges. HDMI usually needs it.
wire [5:0] SD_R_O;
wire [5:0] SD_G_O;
wire [5:0] SD_B_O;
wire [OUT_COLOR_DEPTH-1:0] SD_R_O;
wire [OUT_COLOR_DEPTH-1:0] SD_G_O;
wire [OUT_COLOR_DEPTH-1:0] SD_B_O;
wire SD_HS_O;
wire SD_VS_O;
wire SD_HB_O;
@@ -67,7 +74,7 @@ wire SD_VB_O;
wire pixel_ena;
scandoubler #(SD_HCNT_WIDTH, COLOR_DEPTH) scandoubler
scandoubler #(SD_HCNT_WIDTH, COLOR_DEPTH, SD_HSCNT_WIDTH, OUT_COLOR_DEPTH) scandoubler
(
.clk_sys ( clk_sys ),
.bypass ( scandoubler_disable ),
@@ -90,11 +97,11 @@ scandoubler #(SD_HCNT_WIDTH, COLOR_DEPTH) scandoubler
.b_out ( SD_B_O )
);
wire [5:0] osd_r_o;
wire [5:0] osd_g_o;
wire [5:0] osd_b_o;
wire [OUT_COLOR_DEPTH-1:0] osd_r_o;
wire [OUT_COLOR_DEPTH-1:0] osd_g_o;
wire [OUT_COLOR_DEPTH-1:0] osd_b_o;
osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR, OSD_AUTO_CE, USE_BLANKS) osd
osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR, OSD_AUTO_CE, USE_BLANKS, OUT_COLOR_DEPTH, BIG_OSD) osd
(
.clk_sys ( clk_sys ),
.rotate ( rotate ),
@@ -102,9 +109,9 @@ osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR, OSD_AUTO_CE, USE_BLANKS) osd
.SPI_DI ( SPI_DI ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS3 ( SPI_SS3 ),
.R_in ( SD_R_O ),
.G_in ( SD_G_O ),
.B_in ( SD_B_O ),
.R_in ( SD_R_O ),
.G_in ( SD_G_O ),
.B_in ( SD_B_O ),
.HBlank ( SD_HB_O ),
.VBlank ( SD_VB_O ),
.HSync ( SD_HS_O ),
@@ -114,14 +121,17 @@ osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR, OSD_AUTO_CE, USE_BLANKS) osd
.B_out ( osd_b_o )
);
wire [5:0] cofi_r, cofi_g, cofi_b;
wire [OUT_COLOR_DEPTH-1:0] cofi_r, cofi_g, cofi_b;
wire cofi_hs, cofi_vs;
wire cofi_hb, cofi_vb;
wire cofi_pixel_ena;
cofi #(6) cofi (
cofi #(OUT_COLOR_DEPTH) cofi (
.clk ( clk_sys ),
.pix_ce ( pixel_ena ),
.enable ( blend ),
.hblank ( USE_BLANKS ? SD_HB_O : ~SD_HS_O ),
.vblank ( SD_VB_O ),
.hs ( SD_HS_O ),
.vs ( SD_VS_O ),
.red ( osd_r_o ),
@@ -129,34 +139,71 @@ cofi #(6) cofi (
.blue ( osd_b_o ),
.hs_out ( cofi_hs ),
.vs_out ( cofi_vs ),
.hblank_out( cofi_hb ),
.vblank_out( cofi_vb ),
.red_out ( cofi_r ),
.green_out( cofi_g ),
.blue_out( cofi_b )
.blue_out( cofi_b ),
.pix_ce_out(cofi_pixel_ena)
);
wire [OUT_COLOR_DEPTH-1:0] cleaner_r_o;
wire [OUT_COLOR_DEPTH-1:0] cleaner_g_o;
wire [OUT_COLOR_DEPTH-1:0] cleaner_b_o;
wire cleaner_hs_o, cleaner_vs_o, cleaner_hb_o, cleaner_vb_o;
video_cleaner #(OUT_COLOR_DEPTH) video_cleaner(
.clk_vid ( clk_sys ),
.ce_pix ( scandoubler_disable ? 1'b1 : cofi_pixel_ena ),
.enable ( VIDEO_CLEANER ),
.R ( cofi_r ),
.G ( cofi_g ),
.B ( cofi_b ),
.HSync ( cofi_hs ),
.VSync ( cofi_vs ),
.HBlank ( cofi_hb ),
.VBlank ( cofi_vb ),
.VGA_R ( cleaner_r_o ),
.VGA_G ( cleaner_g_o ),
.VGA_B ( cleaner_b_o ),
.VGA_VS ( cleaner_vs_o),
.VGA_HS ( cleaner_hs_o),
.HBlank_out ( cleaner_hb_o),
.VBlank_out ( cleaner_vb_o)
);
wire hs, vs, cs;
wire [5:0] r,g,b;
wire hb, vb;
wire [OUT_COLOR_DEPTH-1:0] r,g,b;
RGBtoYPbPr #(6) rgb2ypbpr
RGBtoYPbPr #(OUT_COLOR_DEPTH) rgb2ypbpr
(
.clk ( clk_sys ),
.ena ( ypbpr ),
.red_in ( cofi_r ),
.green_in ( cofi_g ),
.blue_in ( cofi_b ),
.hs_in ( cofi_hs ),
.vs_in ( cofi_vs ),
.cs_in ( SYNC_AND ? (cofi_hs & cofi_vs) : ~(cofi_hs ^ cofi_vs) ),
.red_out ( r ),
.green_out ( g ),
.blue_out ( b ),
.hs_out ( hs ),
.vs_out ( vs ),
.cs_out ( cs )
.red_in ( cleaner_r_o ),
.green_in ( cleaner_g_o ),
.blue_in ( cleaner_b_o ),
.hs_in ( cleaner_hs_o ),
.vs_in ( cleaner_vs_o ),
.cs_in ( SYNC_AND ? (cleaner_hs_o & cleaner_vs_o) : ~(cleaner_hs_o ^ cleaner_vs_o) ),
.hb_in ( cleaner_hb_o ),
.vb_in ( cleaner_vb_o ),
.red_out ( r ),
.green_out ( g ),
.blue_out ( b ),
.hs_out ( hs ),
.vs_out ( vs ),
.cs_out ( cs ),
.hb_out ( hb ),
.vb_out ( vb )
);
always @(posedge clk_sys) begin
VGA_R <= r;
VGA_G <= g;
VGA_B <= b;
@@ -164,5 +211,9 @@ always @(posedge clk_sys) begin
// and VCC on VGA_VS (to switch into rgb mode)
VGA_HS <= ((~no_csync & scandoubler_disable) || ypbpr)? cs : hs;
VGA_VS <= ((~no_csync & scandoubler_disable) || ypbpr)? 1'b1 : vs;
VGA_HB <= hb;
VGA_VB <= vb;
VGA_DE <= ~(hb | vb);
end
endmodule

View File

@@ -15,18 +15,18 @@ module osd (
input [1:0] rotate, //[0] - rotate [1] - left or right
// VGA signals coming from core
input [5:0] R_in,
input [5:0] G_in,
input [5:0] B_in,
input [OUT_COLOR_DEPTH-1:0] R_in,
input [OUT_COLOR_DEPTH-1:0] G_in,
input [OUT_COLOR_DEPTH-1:0] B_in,
input HBlank,
input VBlank,
input HSync,
input VSync,
// VGA signals going to video connector
output [5:0] R_out,
output [5:0] G_out,
output [5:0] B_out
output [OUT_COLOR_DEPTH-1:0] R_out,
output [OUT_COLOR_DEPTH-1:0] G_out,
output [OUT_COLOR_DEPTH-1:0] B_out
);
parameter OSD_X_OFFSET = 11'd0;
@@ -34,9 +34,12 @@ parameter OSD_Y_OFFSET = 11'd0;
parameter OSD_COLOR = 3'd0;
parameter OSD_AUTO_CE = 1'b1;
parameter USE_BLANKS = 1'b0;
parameter OUT_COLOR_DEPTH = 6;
parameter BIG_OSD = 1'b0;
localparam OSD_WIDTH = 11'd256;
localparam OSD_HEIGHT = 11'd128;
localparam OSD_LINES = 8 << BIG_OSD;
localparam OSD_WIDTH_PADDED = OSD_WIDTH + (OSD_WIDTH >> 1); // 25% padding left and right
@@ -47,12 +50,12 @@ localparam OSD_WIDTH_PADDED = OSD_WIDTH + (OSD_WIDTH >> 1); // 25% padding left
// this core supports only the display related OSD commands
// of the minimig
reg osd_enable;
(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[2047:0]; // the OSD buffer itself
(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[256*OSD_LINES-1:0]; // the OSD buffer itself
// the OSD has its own SPI interface to the io controller
always@(posedge SPI_SCK, posedge SPI_SS3) begin
reg [4:0] cnt;
reg [10:0] bcnt;
reg [11:0] bcnt;
reg [7:0] sbuf;
reg [7:0] cmd;
@@ -69,15 +72,15 @@ always@(posedge SPI_SCK, posedge SPI_SS3) begin
if(cnt == 7) begin
cmd <= {sbuf[6:0], SPI_DI};
// lower three command bits are line address
bcnt <= {sbuf[1:0], SPI_DI, 8'h00};
// lower four command bits are line address
bcnt <= {sbuf[2:0], SPI_DI, 8'h00};
// command 0x40: OSDCMDENABLE, OSDCMDDISABLE
if(sbuf[6:3] == 4'b0100) osd_enable <= SPI_DI;
end
// command 0x20: OSDCMDWRITE
if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin
if((cmd[7:4] == 4'b0010) && (cnt == 15)) begin
osd_buffer[bcnt] <= {sbuf[6:0], SPI_DI};
bcnt <= bcnt + 1'd1;
end
@@ -103,20 +106,23 @@ wire [10:0] dsp_height = (vs_pol & !USE_BLANKS) ? vs_low : vs_high;
wire doublescan = (dsp_height>350);
reg auto_ce_pix;
always @(posedge clk_sys) begin
always @(posedge clk_sys) begin : cedetect
reg [15:0] cnt = 0;
reg [2:0] pixsz;
reg [2:0] pixcnt;
reg hs;
reg hb;
cnt <= cnt + 1'd1;
hs <= HSync;
hb <= HBlank;
pixcnt <= pixcnt + 1'd1;
if(pixcnt == pixsz) pixcnt <= 0;
auto_ce_pix <= !pixcnt;
if(hs && ~HSync) begin
if((!USE_BLANKS && hs && ~HSync) ||
( USE_BLANKS && ~hb && HBlank)) begin
cnt <= 0;
if(cnt <= OSD_WIDTH_PADDED * 2) pixsz <= 0;
else if(cnt <= OSD_WIDTH_PADDED * 3) pixsz <= 1;
@@ -128,6 +134,7 @@ always @(posedge clk_sys) begin
pixcnt <= 0;
auto_ce_pix <= 1;
end
if (USE_BLANKS && HBlank) cnt <= 0;
end
wire ce_pix = OSD_AUTO_CE ? auto_ce_pix : ce;
@@ -206,19 +213,29 @@ wire [10:0] osd_vcnt = v_cnt - v_osd_start;
wire [10:0] osd_hcnt_next = osd_hcnt + 2'd1; // one pixel offset for osd byte address register
reg osd_de;
reg [10:0] osd_buffer_addr;
reg [11:0] osd_buffer_addr;
wire [7:0] osd_byte = osd_buffer[osd_buffer_addr];
reg osd_pixel;
always @(posedge clk_sys) begin
if(ce_pix) begin
osd_buffer_addr <= rotate[0] ? {rotate[1] ? osd_hcnt_next[7:5] : ~osd_hcnt_next[7:5],
rotate[1] ? (doublescan ? ~osd_vcnt[7:0] : ~{osd_vcnt[6:0], 1'b0}) :
(doublescan ? osd_vcnt[7:0] : {osd_vcnt[6:0], 1'b0})} :
{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt_next[7:0]};
if (!BIG_OSD) begin
osd_buffer_addr <= rotate[0] ? {rotate[1] ? osd_hcnt_next[7:5] : ~osd_hcnt_next[7:5],
rotate[1] ? (doublescan ? ~osd_vcnt[7:0] : ~{osd_vcnt[6:0], 1'b0}) :
(doublescan ? osd_vcnt[7:0] : {osd_vcnt[6:0], 1'b0})} :
{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt_next[7:0]};
osd_pixel <= rotate[0] ? osd_byte[rotate[1] ? osd_hcnt[4:2] : ~osd_hcnt[4:2]] :
osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]];
osd_pixel <= rotate[0] ? osd_byte[rotate[1] ? osd_hcnt[4:2] : ~osd_hcnt[4:2]] :
osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]];
end else begin
osd_buffer_addr <= rotate[0] ? {rotate[1] ? osd_hcnt_next[7:4] : ~osd_hcnt_next[7:4],
rotate[1] ? (doublescan ? ~osd_vcnt[7:0] : ~{osd_vcnt[6:0], 1'b0}) :
(doublescan ? osd_vcnt[7:0] : {osd_vcnt[6:0], 1'b0})} :
{doublescan ? osd_vcnt[7:4] : osd_vcnt[6:3], osd_hcnt_next[7:0]};
osd_pixel <= rotate[0] ? osd_byte[rotate[1] ? osd_hcnt[3:1] : ~osd_hcnt[3:1]] :
osd_byte[doublescan ? osd_vcnt[3:1] : osd_vcnt[2:0]];
end
osd_de <= osd_enable &&
((USE_BLANKS && !HBlank) || (!USE_BLANKS && HSync != hs_pol)) && (h_cnt >= h_osd_start) && (h_cnt < h_osd_end) &&
@@ -226,8 +243,8 @@ always @(posedge clk_sys) begin
end
end
assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[5:3]};
assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[5:3]};
assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[5:3]};
assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[OUT_COLOR_DEPTH-1:3]};
assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[OUT_COLOR_DEPTH-1:3]};
assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[OUT_COLOR_DEPTH-1:3]};
endmodule

View File

@@ -2,6 +2,7 @@
// Copyright 2020/2021 by Alastair M. Robinson
(* altera_attribute = "-name AUTO_SHIFT_REGISTER_RECOGNITION OFF" *)
module RGBtoYPbPr
(
input clk,
@@ -12,6 +13,8 @@ module RGBtoYPbPr
input [WIDTH-1:0] blue_in,
input hs_in,
input vs_in,
input hb_in,
input vb_in,
input cs_in,
input pixel_in,
@@ -20,6 +23,8 @@ module RGBtoYPbPr
output [WIDTH-1:0] blue_out,
output reg hs_out,
output reg vs_out,
output reg hb_out,
output reg vb_out,
output reg cs_out,
output reg pixel_out
);
@@ -46,6 +51,8 @@ reg hs_d;
reg vs_d;
reg cs_d;
reg pixel_d;
reg hb_d;
reg vb_d;
assign red_out = r[8+WIDTH-1:8];
assign green_out = y[8+WIDTH-1:8];
@@ -57,6 +64,8 @@ always @(posedge clk) begin
vs_d <= vs_in; // so they're delayed the same amount as the incoming video
cs_d <= cs_in;
pixel_d <= pixel_in;
hb_d <= hb_in;
vb_d <= vb_in;
if(ena) begin
// (Y = 0.299*R + 0.587*G + 0.114*B)
@@ -88,6 +97,8 @@ always @(posedge clk) begin
vs_out <= vs_d;
cs_out <= cs_d;
pixel_out <= pixel_d;
hb_out <= hb_d;
vb_out <= vb_d;
if(ena) begin
y <= r_y + g_y + b_y;

View File

@@ -16,8 +16,6 @@
// 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
// AMR - generates and output a pixel clock with a reliable phase relationship with
// with the scandoubled hsync pulse. Allows the incoming data to be sampled more
// sparsely, reducing block RAM usage. ce_x1/x2 are replaced with a ce_divider
@@ -56,48 +54,48 @@ module scandoubler
output vb_out,
output hs_out,
output vs_out,
output [5:0] r_out,
output [5:0] g_out,
output [5:0] b_out
output [OUT_COLOR_DEPTH-1:0] r_out,
output [OUT_COLOR_DEPTH-1:0] g_out,
output [OUT_COLOR_DEPTH-1:0] b_out
);
parameter HCNT_WIDTH = 9; // Resolution of scandoubler buffer
parameter COLOR_DEPTH = 6; // Bits per colour to be stored in the buffer
parameter HSCNT_WIDTH = 12; // Resolution of hsync counters
parameter OUT_COLOR_DEPTH = 6; // Bits per color outputted
// --------------------- create output signals -----------------
// latch everything once more to make it glitch free and apply scanline effect
reg scanline;
reg [5:0] r;
reg [5:0] g;
reg [5:0] b;
reg [OUT_COLOR_DEPTH-1:0] r;
reg [OUT_COLOR_DEPTH-1:0] g;
reg [OUT_COLOR_DEPTH-1:0] b;
wire [COLOR_DEPTH*3-1:0] sd_mux = bypass ? {r_in, g_in, b_in} : sd_out[COLOR_DEPTH*3-1:0];
localparam m = OUT_COLOR_DEPTH/COLOR_DEPTH;
localparam n = OUT_COLOR_DEPTH%COLOR_DEPTH;
always @(*) begin
if (COLOR_DEPTH == 6) begin
b = sd_mux[5:0];
g = sd_mux[11:6];
r = sd_mux[17:12];
end else if (COLOR_DEPTH == 2) begin
b = {3{sd_mux[1:0]}};
g = {3{sd_mux[3:2]}};
r = {3{sd_mux[5:4]}};
end else if (COLOR_DEPTH == 1) begin
b = {6{sd_mux[0]}};
g = {6{sd_mux[1]}};
r = {6{sd_mux[2]}};
if (n>0) begin
b = { {m{sd_mux[COLOR_DEPTH-1:0]}}, sd_mux[COLOR_DEPTH-1 -:n] };
g = { {m{sd_mux[COLOR_DEPTH*2-1:COLOR_DEPTH]}}, sd_mux[COLOR_DEPTH*2-1 -:n] };
r = { {m{sd_mux[COLOR_DEPTH*3-1:COLOR_DEPTH*2]}}, sd_mux[COLOR_DEPTH*3-1 -:n] };
end else begin
b = { sd_mux[COLOR_DEPTH-1:0], sd_mux[COLOR_DEPTH-1 -:(6-COLOR_DEPTH)] };
g = { sd_mux[COLOR_DEPTH*2-1:COLOR_DEPTH], sd_mux[COLOR_DEPTH*2-1 -:(6-COLOR_DEPTH)] };
r = { sd_mux[COLOR_DEPTH*3-1:COLOR_DEPTH*2], sd_mux[COLOR_DEPTH*3-1 -:(6-COLOR_DEPTH)] };
b = { {m{sd_mux[COLOR_DEPTH-1:0]}} };
g = { {m{sd_mux[COLOR_DEPTH*2-1:COLOR_DEPTH]}} };
r = { {m{sd_mux[COLOR_DEPTH*3-1:COLOR_DEPTH*2]}} };
end
end
reg [12:0] r_mul;
reg [12:0] g_mul;
reg [12:0] b_mul;
reg [OUT_COLOR_DEPTH+6:0] r_mul;
reg [OUT_COLOR_DEPTH+6:0] g_mul;
reg [OUT_COLOR_DEPTH+6:0] b_mul;
reg hb_o;
reg vb_o;
reg hs_o;
reg vs_o;
wire scanline_bypass = (!scanline) | (!(|scanlines)) | bypass;
@@ -113,7 +111,9 @@ wire [6:0] scanline_coeff = scanline_bypass ?
always @(posedge clk_sys) begin
if(ce_x2) begin
hs_o <= hs_sd;
vs_o <= vs_in;
vs_o <= vs_sd;
hb_o <= hb_sd;
vb_o <= vb_sd;
// reset scanlines at every new screen
if(vs_o != vs_in) scanline <= 0;
@@ -127,36 +127,30 @@ always @(posedge clk_sys) begin
end
end
wire [5:0] r_o = r_mul[11:6];
wire [5:0] g_o = g_mul[11:6];
wire [5:0] b_o = b_mul[11:6];
wire hb_o = hb_sd;
wire vb_o = vb_sd;
reg hs_o;
reg vs_o;
wire [OUT_COLOR_DEPTH-1:0] r_o = r_mul[OUT_COLOR_DEPTH+5 -:OUT_COLOR_DEPTH];
wire [OUT_COLOR_DEPTH-1:0] g_o = g_mul[OUT_COLOR_DEPTH+5 -:OUT_COLOR_DEPTH];
wire [OUT_COLOR_DEPTH-1:0] b_o = b_mul[OUT_COLOR_DEPTH+5 -:OUT_COLOR_DEPTH];
// Output multiplexing
wire blank_out = hb_out | vb_out;
assign r_out = blank_out ? {COLOR_DEPTH{1'b0}} : bypass ? r : r_o;
assign g_out = blank_out ? {COLOR_DEPTH{1'b0}} : bypass ? g : g_o;
assign b_out = blank_out ? {COLOR_DEPTH{1'b0}} : bypass ? b : b_o;
assign r_out = blank_out ? {OUT_COLOR_DEPTH{1'b0}} : bypass ? r : r_o;
assign g_out = blank_out ? {OUT_COLOR_DEPTH{1'b0}} : bypass ? g : g_o;
assign b_out = blank_out ? {OUT_COLOR_DEPTH{1'b0}} : bypass ? b : b_o;
assign hb_out = bypass ? hb_in : hb_o;
assign vb_out = bypass ? vb_in : vb_o;
assign hs_out = bypass ? hs_in : hs_o;
assign vs_out = bypass ? vs_in : vs_o;
assign pixel_ena = bypass ? ce_x1 : ce_x2;
// scan doubler output register
reg [3+COLOR_DEPTH*3-1:0] sd_out;
reg [COLOR_DEPTH*3-1:0] sd_out;
// ==================================================================
// ======================== the line buffers ========================
// ==================================================================
// 2 lines of 2**HCNT_WIDTH pixels 3*COLOR_DEPTH bit RGB
(* ramstyle = "no_rw_check" *) reg [3+COLOR_DEPTH*3-1:0] sd_buffer[2*2**HCNT_WIDTH];
(* ramstyle = "no_rw_check" *) reg [COLOR_DEPTH*3-1:0] sd_buffer[2*2**HCNT_WIDTH];
// use alternating sd_buffers when storing/reading data
reg line_toggle;
@@ -165,6 +159,10 @@ reg line_toggle;
reg [HCNT_WIDTH-1:0] hcnt;
reg [HSCNT_WIDTH:0] hs_max;
reg [HSCNT_WIDTH:0] hs_rise;
reg [HCNT_WIDTH:0] hb_fall[2];
reg [HCNT_WIDTH:0] hb_rise[2];
reg [HCNT_WIDTH+1:0] vb_event[2];
reg [HCNT_WIDTH+1:0] vs_event[2];
reg [HSCNT_WIDTH:0] synccnt;
// Input pixel clock, aligned with input sync:
@@ -178,12 +176,21 @@ wire ce_x1 = (i_div == ce_divider_in);
always @(posedge clk_sys) begin
reg hsD, vsD;
reg vbD;
reg hbD;
// Pixel logic on x1 clkena
if(ce_x1) begin
hcnt <= hcnt + 1'd1;
vsD <= vs_in;
vbD <= vb_in;
sd_buffer[{line_toggle, hcnt}] <= {vbD & ~vb_in, ~vbD & vb_in, hb_in, r_in, g_in, b_in};
sd_buffer[{line_toggle, hcnt}] <= {r_in, g_in, b_in};
if (vbD ^ vb_in) vb_event[line_toggle] <= {1'b1, vb_in, hcnt};
if (vsD ^ vs_in) vs_event[line_toggle] <= {1'b1, vs_in, hcnt};
// save position of hblank
hbD <= hb_in;
if(!hbD && hb_in) hb_rise[line_toggle] <= {1'b1, hcnt};
if( hbD && !hb_in) hb_fall[line_toggle] <= {1'b1, hcnt};
end
// Generate pixel clock
@@ -209,10 +216,13 @@ always @(posedge clk_sys) begin
if(!hsD && hs_in) hs_rise <= {1'b0,synccnt[HSCNT_WIDTH:1]};
// begin of incoming hsync
if(hsD && !hs_in) line_toggle <= !line_toggle;
vsD <= vs_in;
if(vsD != vs_in) line_toggle <= 0;
if(hsD && !hs_in) begin
line_toggle <= !line_toggle;
vb_event[!line_toggle] <= 0;
vs_event[!line_toggle] <= 0;
hb_rise[!line_toggle][HCNT_WIDTH] <= 0;
hb_fall[!line_toggle][HCNT_WIDTH] <= 0;
end
end
@@ -223,10 +233,9 @@ end
reg [HSCNT_WIDTH:0] sd_synccnt;
reg [HCNT_WIDTH-1:0] sd_hcnt;
reg vb_sd = 0;
wire vb_on = sd_out[COLOR_DEPTH*3+1];
wire vb_off = sd_out[COLOR_DEPTH*3+2];
reg hb_sd = 0;
reg hs_sd = 0;
reg vs_sd = 0;
// Output pixel clock, aligned with output sync:
reg [2:0] sd_i_div;
@@ -244,11 +253,18 @@ always @(posedge clk_sys) begin
// read data from line sd_buffer
sd_out <= sd_buffer[{~line_toggle, sd_hcnt}];
if (vb_on) vb_sd <= 1;
if (vb_off) vb_sd <= 0;
hb_sd <= sd_out[COLOR_DEPTH*3];
// Handle VBlank event
if(vb_event[~line_toggle][HCNT_WIDTH+1] && sd_hcnt == vb_event[~line_toggle][HCNT_WIDTH-1:0]) vb_sd <= vb_event[~line_toggle][HCNT_WIDTH];
// Handle VSync event
if(vs_event[~line_toggle][HCNT_WIDTH+1] && sd_hcnt == vs_event[~line_toggle][HCNT_WIDTH-1:0]) vs_sd <= vs_event[~line_toggle][HCNT_WIDTH];
// Handle HBlank events
if(hb_rise[~line_toggle][HCNT_WIDTH] && sd_hcnt == hb_rise[~line_toggle][HCNT_WIDTH-1:0]) hb_sd <= 1;
if(hb_fall[~line_toggle][HCNT_WIDTH] && sd_hcnt == hb_fall[~line_toggle][HCNT_WIDTH-1:0]) hb_sd <= 0;
end
sd_i_div <= sd_i_div + 1'd1;
if (sd_i_div==ce_divider_adj) sd_i_div <= 3'b000;
// Framing logic on sysclk
sd_synccnt <= sd_synccnt + 1'd1;
hsD <= hs_in;
@@ -256,13 +272,6 @@ always @(posedge clk_sys) begin
if(sd_synccnt == hs_max || (hsD && !hs_in)) begin
sd_synccnt <= 0;
sd_hcnt <= 0;
end
sd_i_div <= sd_i_div + 1'd1;
if (sd_i_div==ce_divider_adj) sd_i_div <= 3'b000;
// replicate horizontal sync at twice the speed
if(sd_synccnt == 0) begin
hs_sd <= 0;
sd_i_div <= 3'b000;
end
@@ -271,4 +280,10 @@ always @(posedge clk_sys) begin
end
wire ce_x4 = sd_i_div[0]; // Faster pixel_ena for higher subdivisions to prevent blending from becoming to coarse.
assign pixel_ena = ce_divider_out > 3'd5 ?
bypass ? ce_x2 : ce_x4 :
bypass ? ce_x1 : ce_x2 ;
endmodule

337
common/mist/spdif.v Normal file
View File

@@ -0,0 +1,337 @@
//-----------------------------------------------------------------
// SPDIF Transmitter
// V0.1
// Ultra-Embedded.com
// Copyright 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for
// use in closed source commercial applications please contact me
// for details.
//-----------------------------------------------------------------
//
// This file is open source HDL; 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 2 of
// the License, or (at your option) any later version.
//
// This 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 file; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//-----------------------------------------------------------------
// altera message_off 10762
// altera message_off 10240
module spdif
(
input clk_i,
input rst_i,
input [31:0] clk_rate_i,
// Output
output spdif_o,
// Audio interface (16-bit x 2 = RL)
input [31:0] sample_i,
output reg sample_req_o
);
// SPDIF bit output enable
// Single cycle pulse synchronous to clk_i which drives
// the output bit rate.
// For 44.1KHz, 44100×32×2×2 = 5,644,800Hz
// For 48KHz, 48000×32×2×2 = 6,144,000Hz
parameter bit_clk = 48000*32*2*2;
reg bit_out_en_i;
reg [31:0] cnt;
wire [31:0] cnt_next = cnt + bit_clk;
always @(posedge clk_i) begin
bit_out_en_i <= 0;
cnt <= cnt_next;
if(cnt_next >= clk_rate_i) begin
cnt <= cnt_next - clk_rate_i;
bit_out_en_i <= 1;
end
end
//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [15:0] audio_sample_q;
reg [8:0] subframe_count_q;
reg load_subframe_q;
reg [7:0] preamble_q;
wire [31:0] subframe_w;
reg [5:0] bit_count_q;
reg bit_toggle_q;
reg spdif_out_q;
reg [5:0] parity_count_q;
reg channel_status_bit_q;
//-----------------------------------------------------------------
// Subframe Counter
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
subframe_count_q <= 9'd0;
else if (load_subframe_q)
begin
// 192 frames (384 subframes) in an audio block
if (subframe_count_q == 9'd383)
subframe_count_q <= 9'd0;
else
subframe_count_q <= subframe_count_q + 9'd1;
end
end
//-----------------------------------------------------------------
// Sample capture
//-----------------------------------------------------------------
reg [15:0] sample_buf_q;
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
audio_sample_q <= 16'h0000;
sample_buf_q <= 16'h0000;
sample_req_o <= 1'b0;
end
else if (load_subframe_q)
begin
// Start of frame (first subframe)?
if (subframe_count_q[0] == 1'b0)
begin
// Use left sample
audio_sample_q <= sample_i[15:0];
// Store right sample
sample_buf_q <= sample_i[31:16];
// Request next sample
sample_req_o <= 1'b1;
end
else
begin
// Use right sample
audio_sample_q <= sample_buf_q;
sample_req_o <= 1'b0;
end
end
else
sample_req_o <= 1'b0;
end
// Timeslots 3 - 0 = Preamble
assign subframe_w[3:0] = 4'b0000;
// Timeslots 7 - 4 = 24-bit audio LSB
assign subframe_w[7:4] = 4'b0000;
// Timeslots 11 - 8 = 20-bit audio LSB
assign subframe_w[11:8] = 4'b0000;
// Timeslots 27 - 12 = 16-bit audio
assign subframe_w[27:12] = audio_sample_q;
// Timeslots 28 = Validity
assign subframe_w[28] = 1'b0; // Valid
// Timeslots 29 = User bit
assign subframe_w[29] = 1'b0;
// Timeslots 30 = Channel status bit
assign subframe_w[30] = channel_status_bit_q ; //was constant 1'b0 enabling copy-bit;
// Timeslots 31 = Even Parity bit (31:4)
assign subframe_w[31] = 1'b0;
//-----------------------------------------------------------------
// Preamble and Channel status bit
//-----------------------------------------------------------------
localparam PREAMBLE_Z = 8'b00010111; // "B" channel A data at start of block
localparam PREAMBLE_Y = 8'b00100111; // "W" channel B data
localparam PREAMBLE_X = 8'b01000111; // "M" channel A data not at start of block
reg [7:0] preamble_r;
reg channel_status_bit_r;
always @ *
begin
// Start of audio block?
// Z(B) - Left channel
if (subframe_count_q == 9'd0)
preamble_r = PREAMBLE_Z; // Z(B)
// Right Channel?
else if (subframe_count_q[0] == 1'b1)
preamble_r = PREAMBLE_Y; // Y(W)
// Left Channel (but not start of block)?
else
preamble_r = PREAMBLE_X; // X(M)
if (subframe_count_q[8:1] == 8'd2) // frame 2 => subframes 4 and 5 => 0 = copy inhibited, 1 = copy permitted
channel_status_bit_r = 1'b1;
else if (subframe_count_q[8:1] == 8'd15) // frame 15 => 0 = no indication, 1 = original media
channel_status_bit_r = 1'b1;
else if (subframe_count_q[8:1] == 8'd25) // frame 24 to 27 => sample frequency, 0100 = 48kHz, 0000 = 44kHz (l2r)
channel_status_bit_r = 1'b1;
else
channel_status_bit_r = 1'b0; // everything else defaults to 0
end
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
preamble_q <= 8'h00;
channel_status_bit_q <= 1'b0;
end
else if (load_subframe_q)
begin
preamble_q <= preamble_r;
channel_status_bit_q <= channel_status_bit_r;
end
end
//-----------------------------------------------------------------
// Parity Counter
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
parity_count_q <= 6'd0;
end
// Time to output a bit?
else if (bit_out_en_i)
begin
// Preamble bits?
if (bit_count_q < 6'd8)
begin
parity_count_q <= 6'd0;
end
// Normal timeslots
else if (bit_count_q < 6'd62)
begin
// On first pass through this timeslot, count number of high bits
if (bit_count_q[0] == 0 && subframe_w[bit_count_q / 2] == 1'b1)
parity_count_q <= parity_count_q + 6'd1;
end
end
end
//-----------------------------------------------------------------
// Bit Counter
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i)
begin
if (rst_i == 1'b1)
begin
bit_count_q <= 6'b0;
load_subframe_q <= 1'b1;
end
// Time to output a bit?
else if (bit_out_en_i)
begin
// 32 timeslots (x2 for double frequency)
if (bit_count_q == 6'd63)
begin
bit_count_q <= 6'd0;
load_subframe_q <= 1'b1;
end
else
begin
bit_count_q <= bit_count_q + 6'd1;
load_subframe_q <= 1'b0;
end
end
else
load_subframe_q <= 1'b0;
end
//-----------------------------------------------------------------
// Bit half toggle
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i)
if (rst_i == 1'b1)
bit_toggle_q <= 1'b0;
// Time to output a bit?
else if (bit_out_en_i)
bit_toggle_q <= ~bit_toggle_q;
//-----------------------------------------------------------------
// Output bit (BMC encoded)
//-----------------------------------------------------------------
reg bit_r;
always @ *
begin
bit_r = spdif_out_q;
// Time to output a bit?
if (bit_out_en_i)
begin
// Preamble bits?
if (bit_count_q < 6'd8)
begin
bit_r = preamble_q[bit_count_q[2:0]];
end
// Normal timeslots
else if (bit_count_q < 6'd62)
begin
if (subframe_w[bit_count_q / 2] == 1'b0)
begin
if (bit_toggle_q == 1'b0)
bit_r = ~spdif_out_q;
else
bit_r = spdif_out_q;
end
else
bit_r = ~spdif_out_q;
end
// Parity timeslot
else
begin
// Even number of high bits, make odd
if (parity_count_q[0] == 1'b0)
begin
if (bit_toggle_q == 1'b0)
bit_r = ~spdif_out_q;
else
bit_r = spdif_out_q;
end
else
bit_r = ~spdif_out_q;
end
end
end
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
spdif_out_q <= 1'b0;
else
spdif_out_q <= bit_r;
assign spdif_o = spdif_out_q;
endmodule

View File

@@ -24,7 +24,7 @@
module user_io (
input [(8*STRLEN)-1:0] conf_str,
output [9:0] conf_addr, // RAM address for config string, if STRLEN=0
output [10:0] conf_addr, // RAM address for config string, if STRLEN=0
input [7:0] conf_chr,
input clk_sys, // clock for system-related messages (kbd, joy, etc...)
@@ -66,7 +66,7 @@ module user_io (
output reg sd_dout_strobe = 0,
input [7:0] sd_din,
output reg sd_din_strobe = 0,
output reg [8:0] sd_buff_addr,
output reg [8+SD_BLKSZ:0] sd_buff_addr,
output reg [SD_IMAGES-1:0] img_mounted, // rising edge if a new image is mounted
output reg [63:0] img_size, // size of image in bytes
@@ -98,6 +98,16 @@ module user_io (
output reg mouse_strobe, // mouse data is valid on mouse_strobe
output reg mouse_idx, // which mouse?
// i2c bridge
output reg i2c_start,
output reg i2c_read,
output reg [6:0] i2c_addr,
output reg [7:0] i2c_subaddr,
output reg [7:0] i2c_dout,
input [7:0] i2c_din,
input i2c_ack,
input i2c_end,
// serial com port
input [7:0] serial_data,
input serial_strobe
@@ -110,13 +120,14 @@ parameter SD_IMAGES=2; // number of block-access images (max. 4 supported in cur
parameter PS2BIDIR=0; // bi-directional PS2 interface
parameter FEATURES=0; // requested features from the firmware
parameter ARCHIE=0;
parameter SD_BLKSZ=1'b0; // blocksize = 512<<SD_BLKSZ
localparam W = $clog2(SD_IMAGES);
reg [6:0] sbuf;
reg [7:0] cmd;
reg [7:0] cmd; // command in SPI_CLK domain
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [9:0] byte_cnt; // counts bytes
reg [10:0] byte_cnt; // counts bytes
reg [7:0] but_sw;
reg [2:0] stick_idx;
@@ -126,7 +137,8 @@ assign scandoubler_disable = but_sw[4];
assign ypbpr = but_sw[5];
assign no_csync = but_sw[6];
assign conf_addr = byte_cnt;
assign conf_addr = byte_cnt + conf_offset - (cmd == 8'h24 ? 2'd3 : 2'd0);
reg [10:0] conf_offset = 0;
// bit 4 indicates ROM direct upload capability
wire [7:0] core_type = ARCHIE ? 8'ha6 : ROM_DIRECT_UPLOAD ? 8'hb4 : 8'ha4;
@@ -237,7 +249,7 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_counter
byte_cnt <= 0;
end else begin
if((bit_cnt == 7)&&(~&byte_cnt))
byte_cnt <= byte_cnt + 8'd1;
byte_cnt <= byte_cnt + 1'd1;
bit_cnt <= bit_cnt + 1'd1;
end
@@ -254,11 +266,11 @@ always@(negedge spi_sck or posedge SPI_SS_IO) begin : spi_byteout
end
end
generate if (ARCHIE) begin
reg [7:0] kbd_out_status;
reg [7:0] kbd_out_data_r;
reg [7:0] kbd_out_status = 0;
reg [7:0] kbd_out_data_r = 0;
reg kbd_out_data_available = 0;
generate if (ARCHIE) begin
always@(negedge spi_sck or posedge SPI_SS_IO) begin : archie_kbd_out
if(SPI_SS_IO == 1) begin
kbd_out_data_r <= 0;
@@ -273,12 +285,13 @@ endgenerate
always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter
reg [31:0] sd_lba_r;
reg [W:0] drive_sel_r;
reg [7:0] drive_sel_r;
reg ps2_kbd_rx_strobeD;
reg ps2_mouse_rx_strobeD;
if(SPI_SS_IO == 1) begin
spi_byte_out <= core_type;
cmd <= 0;
end else begin
// read the command byte to choose the response
if(bit_cnt == 7) begin
@@ -309,11 +322,18 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter
8'h14: if (STRLEN == 0) spi_byte_out <= conf_chr; else
if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8];
// reading config string with offset
8'h24: if(byte_cnt == 0) spi_byte_out <= 8'hAA; else // indicating the command is supported
if (STRLEN == 0) spi_byte_out <= conf_chr; else
if((byte_cnt + conf_offset - 2'd3) < STRLEN) spi_byte_out <= conf_str[(STRLEN - (byte_cnt + conf_offset - 2'd3) - 1)<<3 +:8];
// reading sd card status
8'h16: if(byte_cnt == 0) begin
spi_byte_out <= sd_cmd;
sd_lba_r <= sd_lba;
drive_sel_r <= drive_sel;
drive_sel_r <= 0;
drive_sel_r[W:0] <= drive_sel;
drive_sel_r[4] <= SD_BLKSZ;
end
else if(byte_cnt == 1) spi_byte_out <= drive_sel_r;
else if(byte_cnt < 6) spi_byte_out <= sd_lba_r[(5-byte_cnt)<<3 +:8];
@@ -331,6 +351,11 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter
if (byte_cnt == 0) spi_byte_out <= 8'h80;
else spi_byte_out <= FEATURES[(4-byte_cnt)<<3 +:8];
// i2c
8'h31:
if (byte_cnt == 0) spi_byte_out <= {6'd0, i2c_ack, i2c_end};
else spi_byte_out <= i2c_din;
endcase
end
end
@@ -390,6 +415,7 @@ always @(posedge clk_sys) begin : cmd_block
mouse_strobe <= 0;
ps2_kbd_tx_strobe <= 0;
ps2_mouse_tx_strobe <= 0;
i2c_start <= 0;
if(ARCHIE) begin
if (kbd_out_strobe) kbd_out_data_available <= 1;
@@ -406,6 +432,7 @@ always @(posedge clk_sys) begin : cmd_block
abyte_cnt <= 0;
mouse_fifo_ok <= 0;
kbd_fifo_ok <= 0;
conf_offset <= 0;
end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin
if(~&abyte_cnt)
@@ -514,6 +541,16 @@ always @(posedge clk_sys) begin : cmd_block
// RTC
8'h22: if(abyte_cnt<9) rtc[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
// get_conf_str_ext
8'h24: if(abyte_cnt == 1) conf_offset[7:0] <= spi_byte_in;
else if (abyte_cnt == 2) conf_offset[10:8] <= spi_byte_in[2:0];
// I2C bridge
8'h30: if(abyte_cnt == 1) {i2c_addr, i2c_read} <= spi_byte_in;
else if (abyte_cnt == 2) i2c_subaddr <= spi_byte_in;
else if (abyte_cnt == 3) begin i2c_dout <= spi_byte_in; i2c_start <= 1; end
endcase
end
end

104
common/mist/video_cleaner.v Normal file
View File

@@ -0,0 +1,104 @@
//
//
// Copyright (c) 2018 Sorgelig
//
// This program is GPL Licensed. See COPYING for the full license.
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
// Align VBlank/VSync to HBlank/HSync edges.
// Warning! Breaks interlaced VSync.
module video_cleaner
(
input clk_vid,
input ce_pix,
input enable,
input [COLOR_DEPTH-1:0] R,
input [COLOR_DEPTH-1:0] G,
input [COLOR_DEPTH-1:0] B,
input HSync,
input VSync,
input HBlank,
input VBlank,
// video output signals
output reg [COLOR_DEPTH-1:0] VGA_R,
output reg [COLOR_DEPTH-1:0] VGA_G,
output reg [COLOR_DEPTH-1:0] VGA_B,
output reg VGA_VS,
output reg VGA_HS,
// optional aligned blank
output reg HBlank_out,
output reg VBlank_out
);
parameter COLOR_DEPTH = 8;
wire hs, vs;
s_fix sync_v(clk_vid, HSync, hs);
s_fix sync_h(clk_vid, VSync, vs);
wire hbl = hs | HBlank;
wire vbl = vs | VBlank;
always @(posedge clk_vid) begin
if(!enable) begin
HBlank_out <= HBlank;
VBlank_out <= VBlank;
VGA_HS <= HSync;
VGA_VS <= VSync;
VGA_R <= R;
VGA_G <= G;
VGA_B <= B;
end else
if(ce_pix) begin
HBlank_out <= hbl;
VGA_HS <= hs;
if(~VGA_HS & hs) VGA_VS <= vs;
VGA_R <= R;
VGA_G <= G;
VGA_B <= B;
if(HBlank_out & ~hbl) VBlank_out <= vbl;
end
end
endmodule
module s_fix
(
input clk,
input sync_in,
output sync_out
);
assign sync_out = sync_in ^ pol;
reg pol;
always @(posedge clk) begin
integer pos = 0, neg = 0, cnt = 0;
reg s1,s2;
s1 <= sync_in;
s2 <= s1;
if(~s2 & s1) neg <= cnt;
if(s2 & ~s1) pos <= cnt;
cnt <= cnt + 1;
if(s2 != s1) cnt <= 0;
pol <= pos > neg;
end
endmodule