diff --git a/common/mist/.gitignore b/common/mist/.gitignore
new file mode 100644
index 00000000..7664704b
--- /dev/null
+++ b/common/mist/.gitignore
@@ -0,0 +1 @@
+*.bak
\ No newline at end of file
diff --git a/common/mist/cofi.sv b/common/mist/cofi.sv
index c519bd5d..c49b55bb 100644
--- a/common/mist/cofi.sv
+++ b/common/mist/cofi.sv
@@ -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
diff --git a/common/mist/data_io.v b/common/mist/data_io.v
index 6862f1f4..3563dad1 100644
--- a/common/mist/data_io.v
+++ b/common/mist/data_io.v
@@ -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
diff --git a/common/mist/i2c_master.v b/common/mist/i2c_master.v
new file mode 100644
index 00000000..1ba6c1a3
--- /dev/null
+++ b/common/mist/i2c_master.v
@@ -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
\ No newline at end of file
diff --git a/common/mist/i2s.v b/common/mist/i2s.v
new file mode 100644
index 00000000..19b70c40
--- /dev/null
+++ b/common/mist/i2s.v
@@ -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
diff --git a/common/mist/mist.qip b/common/mist/mist.qip
index 923b5289..a3eb1346 100644
--- a/common/mist/mist.qip
+++ b/common/mist/mist.qip
@@ -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]
diff --git a/common/mist/mist.vhd b/common/mist/mist.vhd
index 10d8af49..d69dab4a 100644
--- a/common/mist/mist.vhd
+++ b/common/mist/mist.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;
diff --git a/common/mist/mist_core.qip b/common/mist/mist_core.qip
index 1de1ee1c..453f00b7 100644
--- a/common/mist/mist_core.qip
+++ b/common/mist/mist_core.qip
@@ -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]
diff --git a/common/mist/mist_video.v b/common/mist/mist_video.v
index 7e90f157..391d3eb4 100644
--- a/common/mist/mist_video.v
+++ b/common/mist/mist_video.v
@@ -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
diff --git a/common/mist/osd.v b/common/mist/osd.v
index e7b769e7..dea543e8 100644
--- a/common/mist/osd.v
+++ b/common/mist/osd.v
@@ -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
diff --git a/common/mist/rgb2ypbpr.v b/common/mist/rgb2ypbpr.v
index ee3afc1a..b96c136f 100644
--- a/common/mist/rgb2ypbpr.v
+++ b/common/mist/rgb2ypbpr.v
@@ -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;
diff --git a/common/mist/scandoubler.v b/common/mist/scandoubler.v
index 8f98ff8e..6c1384c9 100644
--- a/common/mist/scandoubler.v
+++ b/common/mist/scandoubler.v
@@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-// 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
diff --git a/common/mist/spdif.v b/common/mist/spdif.v
new file mode 100644
index 00000000..2c9ce78f
--- /dev/null
+++ b/common/mist/spdif.v
@@ -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
diff --git a/common/mist/user_io.v b/common/mist/user_io.v
index 80bf1a87..89bd3da7 100644
--- a/common/mist/user_io.v
+++ b/common/mist/user_io.v
@@ -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< neg;
+end
+
+endmodule