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:
1
common/mist/.gitignore
vendored
Normal file
1
common/mist/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.bak
|
||||
@@ -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
|
||||
|
||||
@@ -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
111
common/mist/i2c_master.v
Normal 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
72
common/mist/i2s.v
Normal 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
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
337
common/mist/spdif.v
Normal 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
|
||||
@@ -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
104
common/mist/video_cleaner.v
Normal 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
|
||||
Reference in New Issue
Block a user