diff --git a/.vscode/settings.json b/.vscode/settings.json index 08c096f..f9f0839 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -68,6 +68,8 @@ "system_error": "cpp", "text_encoding": "cpp", "thread": "cpp", - "typeindex": "cpp" + "typeindex": "cpp", + "iterator": "cpp", + "random": "cpp" } } \ No newline at end of file diff --git a/README.md b/README.md index dff58ad..c236fd7 100644 --- a/README.md +++ b/README.md @@ -23,27 +23,22 @@ CD images can be stored as CHD or CUE/BIN format. Core Utilization: - Logic utilization (in ALMs) 13,431 / 41,910 ( 32 % ) - Total registers 15619 + Logic utilization (in ALMs) 13,425 / 41,910 ( 32 % ) + Total registers 15587 Total block memory bits 630,471 / 5,662,720 ( 11 % ) Total DSP Blocks 66 / 112 ( 59 % ) ### TODOs in order of priority -* Fix audio regression during Hotel Mario Score Screen (was ok in 250214) -* Investigate hangup during Wand of Gamelon Shopkeeper cutscene * Find a better solution for reducing CPU speed * Fix regression: Audio hiccups during Philips Logo in Burn:Cycle * A workaround is CPU overclocking * Investigate mysterious non loading behavior -* Investigate "Zelda's Adventure" sound hiccups - * During stop of audiomap and switch to audio channel playback - the audio channel mask is set one sector too late. -* Investigate sound hiccups in both 2D Zelda games - * Occurs during "Help-Cutscene" when SFX is played - * Probably the same as with "Zelda's Adventure" +* Investigate input responsiveness (skipped events?) +* Investigate graphical glitch on the left edge in "Alice in Wonderland" and "Laser Lords" +* Investigate graphical glitch at the bottom of the screen in Kether during pause * Investigate screeching sound effect in the menu of "Golf Tips" -* Fix hang on audio track stop or change +* Fix hang on audio track stop or change in media player * Investigate "Gray border glitch" at the top of "Myst" gameplay (seems to be only one plane) * Fix reset behaviour (Core is sometimes hanging after reset) * Add auto start of titles using front panel "Play" button @@ -103,9 +98,22 @@ by emulation errors but are also present on the real machine. The video data is changed while it is displayed. * When I load a save game in "Burn:Cycle" it plays a short and unclean loop of noise until I do something * I thought that was a bug in the core at first too. However, it is actually like this on a real CD-i too. +* The music of Burn:Cycle sometimes has "pops" and "clicks" + * This game is special. It doesn't play music from CD like most games for this system would do. + * Small loops of sampled music are loaded from CD, stored in memory and randomly concatenated together + to create the background music. These samples are sometimes not very "loopable" creating a pop at looping points. + * This issue is reproducible on a real 210/05 as well +* The music during the Philips Logo animation of Burn:Cycle has broken audio + * This issue is reproducible on a real 210/05 as well + * The problem can be fixed by overclocking the CPU * Burn:Cycle - Random flickering animated text in front of the "Psychic Roulette" credit card terminal * This actually happens on the real machine. I also thought this might be a CPU speed issue, considering that the flickering disappears if the CPU is slightly overclocked. * Flashback: The audio and video during the intro are asynchronous - * This curiously happens on the real machine as well and doesn't depend on 50 or 60 Hz. + * This curiously happens on the real machine as well and doesn't depend on 50 or 60 Hz +* When dying in "Zelda's Adventure" the accompanying sound effect doesn't match the audio data on CD + * Good catch! This is a programming error which can be reproduced on a real CD-i 210/05 as well, + which causes the audio playback to start one sector too late. + * The same phenomenon exists in the "Help cutscene" of "Zelda - Wand of Gamelon" + * It is not audible in that game, because of silence in the beginning diff --git a/rtl/audiodecoder.sv b/rtl/audiodecoder.sv index 495eddd..f261f43 100644 --- a/rtl/audiodecoder.sv +++ b/rtl/audiodecoder.sv @@ -22,10 +22,8 @@ module audiodecoder ( audiostream.source out, output bit sample_channel, - input use_external_coding, // don't read coding from memory, use parameter - input header_coding_s cd_audio_coding, // used when external_coding set + input cdda_mode, // don't read coding from memory, just go for CDDA input start_playback, - input audio_tick, // CD sector tick rate 75 Hz output header_coding_s playback_coding_out, input [12:0] playback_addr, @@ -38,7 +36,6 @@ module audiodecoder ( // XA ADPCM handling DETECT_CODING, DETECT_CODING2, - WAIT_AUDIO_TICKS, EVALHEADER, EVALHEADER2, READ_SAMPLE, @@ -195,16 +192,17 @@ module audiodecoder ( stop_playback_latch <= 0; if (start_playback) begin // Coding can be read from memory or forced - if (use_external_coding) begin + if (cdda_mode) begin // Don't read coding from memory. // Use cd_audio_coding block_cnt <= 0; group_cnt <= 0; - $display("EXTERNAL CODING %x", cd_audio_coding); + playback_coding.rate <= k44Khz; + playback_coding.bps <= k16Bps; + playback_coding.chan <= kStereo; - playback_coding <= cd_audio_coding; - decoder_state <= (cd_audio_coding.bps == k16Bps) ? CDDA_READ : WAIT_AUDIO_TICKS; + decoder_state <= CDDA_READ; end else begin // Read coding from sector header decoder_state <= DETECT_CODING; @@ -249,14 +247,6 @@ module audiodecoder ( end end - WAIT_AUDIO_TICKS: begin - if (audio_tick) decoder_state <= EVALHEADER; - - if (stop_playback_latch) begin - decoder_state <= IDLE; - stop_playback_latch <= 0; - end - end EVALHEADER: begin if (mem_ack) begin data_addr <= block_addr + data_offset; diff --git a/rtl/audiofifo.sv b/rtl/audiofifo.sv index 6255b6b..5be18b0 100644 --- a/rtl/audiofifo.sv +++ b/rtl/audiofifo.sv @@ -5,7 +5,8 @@ module audiofifo ( input reset, audiostream.sink in, audiostream.source out, - output nearly_full + output nearly_full, + output nearly_empty ); bit signed [15:0] mem[64]; @@ -20,12 +21,13 @@ module audiofifo ( bit indizes_equal_during_write_d; bit indizes_equal_during_write_q; - assign out.write = count != 0 && !reset && !indizes_equal_during_write_q; - assign in.strobe = count < 60 && !reset && in.write; + assign out.write = count != 0 && !reset && !indizes_equal_during_write_q; + assign in.strobe = count < 60 && !reset && in.write; // Always a minimum of 28 XA samples per block // We go for 48 just to be safe assign nearly_full = count >= 48; + assign nearly_empty = count <= 3; always_comb begin read_index_d = read_index_q; diff --git a/rtl/audioplayer.sv b/rtl/audioplayer.sv index 87caae6..31124c0 100644 --- a/rtl/audioplayer.sv +++ b/rtl/audioplayer.sv @@ -6,7 +6,6 @@ module audioplayer ( input clk, input sample_tick37, input sample_tick44, - input audio_tick, input reset, output bit [12:0] mem_addr, @@ -15,18 +14,15 @@ module audioplayer ( input mem_ack, input mem_ack_q, - input header_coding_s cd_audio_coding, - input start_playback, // flag starts CD sector playback at playback_addr - input abort_playback_request, - input enable_audiomap, - input disable_audiomap, - input [12:0] playback_addr, + input start_playback, + input stop_playback, + input cdda_mode, + output bit playback_active, + output bit finished_buffer_playback, + output decoder_disable_audiomap, output bit signed [15:0] audio_left, - output bit signed [15:0] audio_right, - output bit audiomap_active, - output bit audiomap_finished_playback, - output decoder_disable_audiomap + output bit signed [15:0] audio_right ); audiostream xa_out (); @@ -42,7 +38,6 @@ module audioplayer ( header_coding_s current_active_coding; wire decoder_idle; - bit playback_request; bit [12:0] playback_request_addr /*verilator public_flat_rd*/; bit decoder_start /*verilator public_flat_rd*/ = 0; @@ -52,8 +47,6 @@ module audioplayer ( .clk(clk), .reset(reset), .reset_filter_on_start(reset_filter_on_start), - .stop_playback(disable_audiomap), - .audio_tick(audio_tick), .mem_addr(mem_addr), .mem_data(mem_data), .mem_rd(mem_rd), @@ -63,55 +56,57 @@ module audioplayer ( .out(xa_out), .sample_channel(xa_channel), - .use_external_coding(!audiomap_active), - .cd_audio_coding(cd_audio_coding), .start_playback(decoder_start), + .stop_playback(stop_playback), + .cdda_mode, .playback_coding_out(current_active_coding), .playback_addr(playback_request_addr), .idle(decoder_idle), .disable_audiomap(decoder_disable_audiomap) ); + wire [1:0] fifo_nearly_full; + wire [1:0] fifo_nearly_empty; + bit fifo_nearly_empty_q; + always_ff @(posedge clk) begin decoder_start <= 0; + fifo_nearly_empty_q <= fifo_nearly_empty[0]; + finished_buffer_playback <= 0; if (reset) begin - playback_request <= 0; - audiomap_active <= 0; + playback_active <= 0; playback_request_addr <= 0; end else begin // Only start playback when decoder is idle - if (decoder_idle && !decoder_start) begin - playback_request <= 0; - decoder_start <= playback_request || (audiomap_active && !decoder_disable_audiomap); - end - - // CD Sector playback - if (start_playback) begin - playback_request <= 1; - playback_request_addr <= playback_addr; + if (decoder_idle && !decoder_start && fifo_nearly_empty[0]) begin + decoder_start <= playback_active && !decoder_disable_audiomap; + finished_buffer_playback <= finished_buffer_playback_latched; end // To react on audiomap activation change - if (enable_audiomap) audiomap_active <= 1; - if (disable_audiomap || decoder_disable_audiomap) audiomap_active <= 0; + if (stop_playback || decoder_disable_audiomap) begin + playback_active <= 0; + end - if (disable_audiomap || abort_playback_request) playback_request <= 0; + // Buffer playback + if (start_playback && !playback_active) begin + playback_active <= 1; + // ADPCM playback always starts at 0x2800 + // For CDDA this might not be accurate + playback_request_addr <= cdda_mode ? 13'h0f00 : 13'h1400; + end // after the decoder was started, change address to the next buffer - if (audiomap_active && decoder_start) begin - playback_request_addr <= playback_request_addr == 13'h1400 ? 13'h1900 : 13'h1400; + if (decoder_start && playback_active) begin + if (cdda_mode) + playback_request_addr <= playback_request_addr == 13'h0a00 ? 13'h0f00 : 13'h0a00; + else + playback_request_addr <= playback_request_addr == 13'h1400 ? 13'h1900 : 13'h1400; end - - // Store playback_request_addr from extern only at start - if (enable_audiomap && !audiomap_active) begin - playback_request_addr <= playback_addr; - end - end end - wire [1:0] fifo_nearly_full; always_comb begin // Mono is default. Write to both FIFOs and ignore the channel @@ -139,26 +134,28 @@ module audioplayer ( .reset, .in(xa_fifo_in[0]), .out(xa_fifo_out[0]), - .nearly_full(fifo_nearly_full[0]) + .nearly_full(fifo_nearly_full[0]), + .nearly_empty(fifo_nearly_empty[0]) ); audiofifo fifo_right ( .clk, .reset, .in(xa_fifo_in[1]), .out(xa_fifo_out[1]), - .nearly_full(fifo_nearly_full[1]) + .nearly_full(fifo_nearly_full[1]), + .nearly_empty(fifo_nearly_empty[1]) ); - bit playback_active = 0; + bit audio_fifo_output_enabled = 0; bit sample_toggle18 = 0; bit decoder_idle_q; - assign reset_filter_on_start = !playback_active; + assign reset_filter_on_start = !audio_fifo_output_enabled; bit strobe_fifo; always_comb begin strobe_fifo = 0; - if (playback_active) begin + if (audio_fifo_output_enabled) begin if (current_active_coding.rate == k44Khz && sample_tick44) strobe_fifo = 1; if (current_active_coding.rate == k37Khz && sample_tick37) strobe_fifo = 1; if (current_active_coding.rate == k18Khz && sample_tick37 && sample_toggle18) @@ -174,20 +171,21 @@ module audioplayer ( // One would have been enough, but let's be sure. // Not having this results into pops especially percievible // with Tetris - bit playback_active_next_sample_tick; + bit audio_fifo_output_enabled_next_sample_tick; + + bit finished_buffer_playback_latched; always_ff @(posedge clk) begin dc_bias_cnt <= !dc_bias_cnt; - audiomap_finished_playback <= 0; decoder_idle_q <= decoder_idle; xa_fifo_out[0].strobe <= 0; xa_fifo_out[1].strobe <= 0; if (reset) begin - playback_active <= 0; - playback_active_next_sample_tick <= 0; + audio_fifo_output_enabled <= 0; + audio_fifo_output_enabled_next_sample_tick <= 0; xa_fifo_out[0].strobe <= 0; xa_fifo_out[1].strobe <= 0; end else begin @@ -195,20 +193,24 @@ module audioplayer ( if (fifo_nearly_full == 2'b11 && ((current_active_coding.rate != k44Khz && sample_tick37) || (current_active_coding.rate == k44Khz && sample_tick44))) begin - playback_active_next_sample_tick <= 1; - playback_active <= playback_active_next_sample_tick; + audio_fifo_output_enabled_next_sample_tick <= 1; + audio_fifo_output_enabled <= audio_fifo_output_enabled_next_sample_tick; end - if (playback_active && decoder_idle && !decoder_idle_q && audiomap_active) begin - audiomap_finished_playback <= 1; + if (audio_fifo_output_enabled && decoder_idle && !decoder_idle_q) begin + finished_buffer_playback_latched <= 1; + end + + if (finished_buffer_playback || stop_playback) begin + finished_buffer_playback_latched <= 0; end if (xa_fifo_out[0].write == 0 && xa_fifo_out[0].write == 0) begin - playback_active <= 0; - playback_active_next_sample_tick <= 0; + audio_fifo_output_enabled <= 0; + audio_fifo_output_enabled_next_sample_tick <= 0; end - if (playback_active) begin + if (audio_fifo_output_enabled) begin if (strobe_fifo) begin xa_fifo_out[0].strobe <= 1; xa_fifo_out[1].strobe <= 1; diff --git a/rtl/cdic.sv b/rtl/cdic.sv index 5fbef6b..7b9c680 100644 --- a/rtl/cdic.sv +++ b/rtl/cdic.sv @@ -61,18 +61,16 @@ module cdic ( bit [31:0] channel_register = 0; // MODE2 Channel Audio Mask - // If matching, disables audiomap and plays sector - // directly without waiting for CPU? - // The data is delivered to one of the ADPCM buffers? + // If matching, the data is delivered to one of the ADPCM buffers bit [15:0] audio_channel_register = 0; bit [15:0] command_register = 0; // DBUF @ 303FFE - // Bit 0 is toggled on every received sector + // Bit 0 is toggled on every received sector and + // points to the just refreshed buffer // Bit 2 is reset on data sector // Bit 2 is set on audio sector - // Bit 14 is set on every received sector // Bit 15 starts the CD reading and parses command register // Resetting Bit 14 stops CD reading // Buffer of the stored sector is visible here @@ -94,6 +92,7 @@ module cdic ( // ABUF @ 303FF4 // Bit 15 causes IRQ // Bit 15 is set when an audio buffer was played + // when bit 13 of AUDCTL is set // Reading register clears bit 15 after the read // The CPU still gets the set bit bit [15:0] audio_buffer_register = 0; @@ -108,17 +107,12 @@ module cdic ( bit [15:0] dma_control_register = 0; // AUDCTL @ 303FFA (called Z buffer in MAME) - // Bit 0 toggles on every read when no audio is played? - // The toggled result is the one returned - // to the CPU? - // Resetting bit 13 stops audio map playback? Or is it bit 11? + // Bit 0 is set when the audiomap has finished playback + // with 0xff coding + // Resetting bit 11 stops audio map playback directly. // CPU does write 0x0000 to do so, ignoring the previous content - // Setting bit 13 starts audio map playback? Or is it bit 11? - // CPU does write 0x2800 to do so, ignoring the previous content - // CPU writes 0x0800 to this register when unmuting - // It does so only if bit 11 is not set but bit 0 is set - // after a CDIC IRQ - // This is also the address for playback of audio + // Setting bit 11 starts audio map playback at ADPCM buffer 0 + // Bit 13 activates IRQs when a single ADPCM buffer was played bit [15:0] audio_control_register = 0; // Matching value for File in MODE2 header @@ -153,6 +147,11 @@ module cdic ( wire sector_tick_audio = sector75counter == 0; wire sample_tick37 /*verilator public_flat_rd*/; wire sample_tick44 /*verilator public_flat_rd*/; + +`ifdef VERILATOR + wire sample_tick /*verilator public_flat_rd*/ = read_cdda ? sample_tick44 : sample_tick37; +`endif + wire sector_tick; flag_cross_domain cross1 ( .clk_a(clk_audio), @@ -237,16 +236,6 @@ module cdic ( .q_b(mem_cdic_readout) ); - // Flag is set after a full sector is received - // which had audio data and matching audio channel and - // needs to be played back now - bit cd_audio_start_playback; - bit cd_audio_abort_playback_request; - - // Address of CD sector to play back - // Should be 13'h1900 or 13'h1400 - // Can be either an audiomap or coming directly from CD - bit [12:0] audio_playback_addr; bit [12:0] mem_cd_audio_addr; // Address for CDIC memory bit mem_cd_audio_rd; @@ -272,18 +261,16 @@ module cdic ( assign audio_left = adpcm_left; assign audio_right = adpcm_right; - wire audiomap_active; - bit adpcm_enable_audiomap; // Flag when audio_control_register[13] is set - bit adpcm_disable_audiomap; // Flag when audio_control_register[13] is reset - wire audiomap_finished_playback; + bit audio_start_playback /*verilator public_flat_rd*/; + bit audio_stop_playback; + wire audio_playback_active /*verilator public_flat_rd*/; + wire finished_audio_buffer_playback; wire decoder_disable_audiomap; - header_coding_s cd_audio_coding; audioplayer adpcm ( .clk(clk), .sample_tick37, .sample_tick44, - .audio_tick(sector_tick), .reset(reset), .mem_addr(mem_cd_audio_addr), .mem_data(mem_cdic_readout), @@ -291,14 +278,11 @@ module cdic ( .mem_ack(mem_cd_audio_ack), .mem_ack_q(mem_cd_audio_ack_q), - .cd_audio_coding(cd_audio_coding), - .start_playback(cd_audio_start_playback), - .abort_playback_request(cd_audio_abort_playback_request), - .enable_audiomap(adpcm_enable_audiomap), - .disable_audiomap(adpcm_disable_audiomap), - .playback_addr(audio_playback_addr), - .audiomap_active(audiomap_active), - .audiomap_finished_playback(audiomap_finished_playback), + .start_playback(audio_start_playback), + .stop_playback(audio_stop_playback), + .cdda_mode(read_cdda), + .playback_active(audio_playback_active), + .finished_buffer_playback(finished_audio_buffer_playback), .decoder_disable_audiomap(decoder_disable_audiomap), .audio_left (adpcm_left), @@ -310,28 +294,6 @@ module cdic ( bit data_target_buffer; bit audio_target_buffer; - always_comb begin -`ifdef VERILATOR - audio_playback_addr = 0; // better visibility in waveform -`else - audio_playback_addr = audio_control_register[13:1]; // optimize LUTs -`endif - - if (adpcm_enable_audiomap) audio_playback_addr = audio_control_register[13:1]; - - // CD Audio Playback - if (cd_audio_start_playback) begin - if (header_mode2) begin - audio_playback_addr = !audio_target_buffer ? 13'h1900 : 13'h1400; - $display("ADPCM at %x", {audio_playback_addr, 1'b0}); - end else begin - assert (read_cdda); - audio_playback_addr = data_target_buffer ? 13'h0f00 : 13'h0a00; - $display("CDDA at %x", {audio_playback_addr, 1'b0}); - end - end - end - bit reset_write_timecode1; bit reset_write_timecode2; bit write_timecode1 = 0; @@ -424,7 +386,8 @@ module cdic ( localparam bit [5:0] kSeekTime = 1; `else // Seeking on a real 210/05 takes about 200ms - localparam bit [5:0] kSeekTime = 14; + // But 19 (250ms) seems to be more stable + localparam bit [5:0] kSeekTime = 19; `endif // Simulates reading time. Remaining sectors to wait. bit [5:0] start_cd_reading_cnt = 0; @@ -445,7 +408,7 @@ module cdic ( end `endif - assign intreq = x_buffer_register[15] | audio_buffer_register[15]; + assign intreq = (x_buffer_register[15] & data_buffer_register[14]) | audio_buffer_register[15]; assign req = dma_control_register[15]; localparam kSectorHeader_Mode = 15 / 2; // Low Byte @@ -459,14 +422,12 @@ module cdic ( always_ff @(posedge clk) begin bus_ack <= 0; rdy <= 0; - cd_audio_start_playback <= 0; - cd_audio_abort_playback_request <= 0; cd_hps_data_valid_q2 <= cd_hps_data_valid_q; cd_hps_data_valid_q <= cd_hps_data_valid; cd_hps_ack_q <= cd_hps_ack; - adpcm_enable_audiomap <= 0; - adpcm_disable_audiomap <= 0; + audio_start_playback <= 0; + audio_stop_playback <= 0; if (reset_write_timecode1) write_timecode1 <= 0; if (reset_write_timecode2) write_timecode2 <= 0; @@ -615,7 +576,6 @@ module cdic ( header_timecode1[7:0], header_timecode2[15:8]); cd_data_target_adr <= audio_target_buffer ? 13'h1904 : 13'h1404; - cd_audio_coding <= header_coding; end else if (use_sector_data && sector_word_index == 10 && !read_raw) begin $display("Use sector %x %x %x for data in buffer %x", header_timecode1[15:8], header_timecode1[7:0], header_timecode2[15:8], { @@ -636,7 +596,7 @@ module cdic ( end // Audio map finished? Cause an IRQ to inform the CPU - if (audiomap_finished_playback) begin + if (finished_audio_buffer_playback && audio_control_register[13]) begin audio_buffer_register[15] <= 1; end @@ -700,9 +660,6 @@ module cdic ( // Bit 2 is set on audio sector data_buffer_register[2] <= header_submode.audio && audio_channel_match && header_mode2; - // Bit 14 is set on every received sector - data_buffer_register[14] <= 1'b1; - // Bit 15 is set when a sector is stored // This causes an IRQ to occur x_buffer_register[15] <= 1'b1; @@ -713,19 +670,9 @@ module cdic ( cd_reading_active <= 0; if (header_submode.audio && audio_channel_match && header_mode2) begin - cd_audio_start_playback <= 1; - // Resetting this bit, causes the CDIC driver to unmute the mixer - audio_control_register[11] <= 0; data_buffer_register[0] <= audio_target_buffer; audio_target_buffer <= !audio_target_buffer; end - - if (read_cdda) begin - cd_audio_start_playback <= 1; - cd_audio_coding.rate <= k44Khz; - cd_audio_coding.bps <= k16Bps; - cd_audio_coding.chan <= kStereo; - end end // Request the next sector from HPS if the last one @@ -754,8 +701,8 @@ module cdic ( read_mode2 <= 1; end 16'h2b: begin - $display("CDIC Command: Stop CDDA"); - cd_reading_active <= 0; + // Unknown purpose + $display("CDIC Command: Stop CDDA?"); end 16'h2e: begin $display("CDIC Command: Update"); @@ -884,9 +831,8 @@ module cdic ( $display("CDIC Write Z Buffer Register / Audio Control Register %x %x", address[13:1], din); audio_control_register <= din; - - adpcm_enable_audiomap <= din[13]; - adpcm_disable_audiomap <= din == 0; + audio_start_playback <= din[11]; + audio_stop_playback <= !din[11]; end 13'h1FFE: begin // 0x3FFC IVEC Interrupt Vector register $display("CDIC Write Interrupt Vector Register %x %x", address[13:1], @@ -912,7 +858,6 @@ module cdic ( audio_control_register[0] <= 0; sector_word_index <= 0; start_cd_reading_cnt <= 0; - cd_audio_abort_playback_request <= 1; end end default: begin @@ -1013,6 +958,7 @@ module cdic ( end 13'h1FFD: begin // 0x3FFA AUDCTL Audio control register dout = audio_control_register; + dout[11] = audio_playback_active; end 13'h1FFE: begin // 0x3FFC IVEC Interrupt Vector register dout = interrupt_vector_register; diff --git a/rtl/cditop.sv b/rtl/cditop.sv index b40c00a..144e6da 100644 --- a/rtl/cditop.sv +++ b/rtl/cditop.sv @@ -268,10 +268,10 @@ module cditop ( .uds(uds), .bus_ack(bus_ack), .bus_err, - .int1(vdsc_int), + .int1(vdsc_int), // Video IRQ .int2(1'b0), // unconnected in CDi MONO1 - .in2(!in2in), // TODO fix polarity - .in4(in4in), + .in2(in2in), // Slave IRQ + .in4(in4in), // CDIC IRQ .in5(1'b0), .iack2(iack2), .iack4(iack4), @@ -345,7 +345,9 @@ module cditop ( wire dtackslaven = ddrb[6] ? portb_out[6] : 1'b1; assign slave_rts = ddrb[4] ? portb_out[4] : 1'b1; - assign in2in = ddrb[5] ? portb_out[5] : 1'b1; + + // The polarity must be altered as a real SCC68070 is low active + assign in2in = !(ddrb[5] ? portb_out[5] : 1'b1); wire datadac = ddrb[0] ? portb_out[0] : 1'b0; wire clkdac = ddrb[1] ? portb_out[1] : 1'b0; @@ -353,7 +355,7 @@ module cditop ( wire csdac2n = ddrb[3] ? portb_out[3] : 1'b1; bit dtackslaven_q = 0; - bit in2in_q = 1; + bit in2in_q = 0; bit slave_irq; @@ -431,14 +433,14 @@ module cditop ( if (reset) begin attex_cs_slave_q <= 0; dtackslaven_q <= 0; - in2in_q <= 1; + in2in_q <= 0; end else begin attex_cs_slave_q <= attex_cs_slave; dtackslaven_q <= dtackslaven; in2in_q <= in2in; - if (!in2in && in2in_q) $display("SLAVE IRQ2 1"); - if (in2in && !in2in_q) $display("SLAVE IRQ2 0"); + if (!in2in && in2in_q) $display("SLAVE IRQ2 0"); + if (in2in && !in2in_q) $display("SLAVE IRQ2 1"); end end diff --git a/sim2/.gitignore b/sim2/.gitignore index 937a28c..d52a09c 100644 --- a/sim2/.gitignore +++ b/sim2/.gitignore @@ -5,3 +5,5 @@ log* *.BIN *.rom +*.wav +*.vcd diff --git a/sim2/cdic_audiomap.asm b/sim2/cdic_audiomap.asm index ff4f47b..bc26a10 100644 --- a/sim2/cdic_audiomap.asm +++ b/sim2/cdic_audiomap.asm @@ -34,14 +34,14 @@ play_audiomap: jsr waitforirq move.b #'A',$80002019 move.w #$8a00,d0 - move.w #$b200,d1 + move.w #$a800,d1 ; 0x2800 jsr movedata move.b #'1',$80002019 jsr waitforirq move.b #'B',$80002019 move.w #$8000,d0 - move.w #$a800,d1 + move.w #$b200,d1; 0x3200 jsr movedata jsr waitforirq @@ -79,10 +79,15 @@ play_some_cd_sectors: ; Wait for the music to play back some sectors jsr waitforirq + + move.w #$0800,$303FFA ; Start playback + jsr waitforirq jsr waitforirq move.w #$0000,$303FFE ; Stop CD reading + move.w #$0000,$303FFA ; Stop playback + rts main: @@ -176,7 +181,7 @@ movedata: move.w $303200,d7 move.w $303202,d7 - move.w #$3200,$303FFA ; Start Audiomap at 0x3200 + move.w #$2800,$303FFA ; Start Audiomap at 0x2800 rts wait: diff --git a/sim2/cdic_cdda_play.asm b/sim2/cdic_cdda_play.asm index ea1285a..624a9a1 100644 --- a/sim2/cdic_cdda_play.asm +++ b/sim2/cdic_cdda_play.asm @@ -17,6 +17,8 @@ main: move.w #$2480,$303FFC ; Interrupt Vector move.w #$0028,$303C00 ; Play CDDA + ;move.w #$0027,$303C00 ; Fetch TOC + ; Apprentice - Level 1 move.l #$19468000,$303C02 ; Timer Register @@ -26,6 +28,9 @@ main: move.w #$C000,$303FFE ; Start the Read by setting bit 15 of the data buffer jsr waitforirq + + move.w #$0800,$303FFA ; Start playback + jsr waitforirq jsr waitforirq jsr waitforirq diff --git a/sim2/cdic_xa_play.asm b/sim2/cdic_xa_play.asm index d6a9bc8..e00bec9 100644 --- a/sim2/cdic_xa_play.asm +++ b/sim2/cdic_xa_play.asm @@ -34,6 +34,12 @@ main: move.w #$4000,$303C0C ; Audio Channel Register move.l #$07494800,$303C02 ; Timer Register + ; Apprentice USA Philips Logo + move.w #$0000,$303C06 ; File Register + move.l #$8000,$303C08 ; Channel Register + move.w #$8000,$303C0C ; Audio Channel Register + move.l #$12215300,$303C02 ; Timer Register + ; Tetris 00 35 68 00356800 Philips Logo Coding 01, 2 channels, 4 bits, 000093a8 frequency ; Tetris 01 42 67 01426700 Main Menu Coding 05, 2 channels, 4 bits, 000049d4 frequency ; Tetris 55 50 33 55503300 Intro Coding 05, 2 channels, 4 bits, 000049d4 frequency @@ -44,11 +50,17 @@ main: move.w #$C000,$303FFE ; Start the Read by setting bit 15 of the data buffer jsr waitforirq + + move.w #$0800,$303FFA ; Start playback + jsr waitforirq jsr waitforirq jsr waitforirq jsr waitforirq + move.w #$0000,$303FFA ; Stop playback + + ;move.w #$0000,$303FFE ; Deactivate cd reading endless: diff --git a/sim2/create_wav.sh b/sim2/create_wav.sh new file mode 100755 index 0000000..6cc137d --- /dev/null +++ b/sim2/create_wav.sh @@ -0,0 +1,4 @@ +sox -M \ + -r 37800 -e signed-integer -b 16 -c 1 -t raw $1/audio_left.bin \ + -r 37800 -e signed-integer -b 16 -c 1 -t raw $1/audio_right.bin \ + $1_audio.wav diff --git a/sim2/produce_test_rom.sh b/sim2/produce_test_rom.sh index c5a39e0..3249716 100755 --- a/sim2/produce_test_rom.sh +++ b/sim2/produce_test_rom.sh @@ -9,12 +9,13 @@ vasmm68k_mot -Fbin -m68000 byte_word_test.asm -o byte_word_test.rom vasmm68k_mot -Fbin -m68000 slavetest.asm -o slavetest.rom vasmm68k_mot -Fbin -m68000 cdic_audiomap.asm -o cdic_audiomap.rom vasmm68k_mot -Fbin -m68000 cdic_cdda_play.asm -o cdic_cdda_play.rom +vasmm68k_mot -Fbin -m68000 cdic_xa_play.asm -o cdic_xa_play.rom vasmm68k_mot -Fbin -m68000 cdic_data.asm -o cdic_data.rom vasmm68k_mot -Fbin -m68000 uarttest.asm -o uarttest.rom vasmm68k_mot -Fbin -m68000 nvram_backup_restore.asm -o nvram_backup_restore.rom vasmm68k_mot -Fbin -m68000 nvramsender.asm -o nvramsender.rom vasmm68k_mot -Fbin -m68000 cdic_sector_send.asm -o cdic_sector_send.rom -xxd -p -c2 cdic_cdda_play.rom cdi200.mem +xxd -p -c2 cdic_xa_play.rom cdi200.mem xxd -p -c1 ../sim/cdimono1/zx405042p__cdi_slave_2.0__b43t__zzmk9213.mc68hc705c8a_withtestrom.7206 slave.mem #dd if=/dev/urandom of=save.bin count=16 diff --git a/sim2/sim_top.cpp b/sim2/sim_top.cpp index 2ff183d..1f334aa 100644 --- a/sim2/sim_top.cpp +++ b/sim2/sim_top.cpp @@ -130,8 +130,10 @@ void subcode_data(int lba, struct subcode &out) { s = fake_lba / 75; f = fake_lba % 75; - if (lba < toc_entry_count) { - auto &toc_entry = toc_buffer[lba]; + int toc_entry_index = lba + 0x10000; + if (lba < 0 && toc_entry_index < toc_entry_count) { + + auto &toc_entry = toc_buffer[toc_entry_index]; out.control = htons(toc_entry.control); out.track = 0; // Track 0 for TOC @@ -146,8 +148,8 @@ void subcode_data(int lba, struct subcode &out) { out.mode1_crc0 = htons(0xff); out.mode1_crc1 = htons(0xff); - // printf("toc lba=%d %02x %02x %02x %02x %02x\n", lba, out.control, out.index, out.mode1_amins, - // out.mode1_asecs, out.mode1_afrac); + // printf("toc lba=%d %02x %02x %02x %02x %02x\n", toc_entry_index, out.control, out.index, out.mode1_amins, + // out.mode1_asecs, out.mode1_afrac); } else { int track = 1; out.control = htons(0x01); @@ -266,7 +268,6 @@ class CDi { } void clock() { - for (int i = 0; i < 2; i++) { dut.rootp->emu__DOT__clk_sys = (sim_time & 1); dut.rootp->emu__DOT__clk_audio = (sim_time & 1); @@ -584,7 +585,7 @@ class CDi { } // Simulate Audio - if (dut.rootp->emu__DOT__cditop__DOT__cdic_inst__DOT__sample_tick44) { + if (dut.rootp->emu__DOT__cditop__DOT__cdic_inst__DOT__sample_tick) { int16_t sample_l = dut.rootp->emu__DOT__cditop__DOT__cdic_inst__DOT__adpcm__DOT__fifo_out_left; int16_t sample_r = dut.rootp->emu__DOT__cditop__DOT__cdic_inst__DOT__adpcm__DOT__fifo_out_right; fwrite(&sample_l, 2, 1, f_audio_left); @@ -629,7 +630,7 @@ class CDi { } dut.eval(); - // do_trace = false; + do_trace = false; dut.rootp->emu__DOT__debug_uart_fake_space = false; dut.rootp->emu__DOT__img_size = 4096; @@ -688,6 +689,86 @@ class CDi { } }; +void prepare_apprentice_usa_toc() { + toc_buffer[0] = {1, 1, 21, 34, 1}; + toc_buffer[1] = {1, 1, 21, 34, 0}; + toc_buffer[2] = {1, 1, 21, 34, 34}; + toc_buffer[3] = {1, 2, 25, 68, 21}; + toc_buffer[4] = {1, 2, 25, 68, 2}; + toc_buffer[5] = {1, 2, 25, 68, 1}; + toc_buffer[6] = {1, 3, 35, 85, 0}; + toc_buffer[7] = {1, 3, 35, 85, 68}; + toc_buffer[8] = {1, 3, 35, 85, 35}; + toc_buffer[9] = {1, 4, 36, 86, 3}; + toc_buffer[10] = {1, 4, 36, 86, 1}; + toc_buffer[11] = {1, 4, 36, 86, 0}; + toc_buffer[12] = {1, 5, 41, 66, 86}; + toc_buffer[13] = {1, 5, 41, 66, 36}; + toc_buffer[14] = {1, 5, 41, 66, 4}; + toc_buffer[15] = {1, 6, 48, 67, 1}; + toc_buffer[16] = {1, 6, 48, 67, 0}; + toc_buffer[17] = {1, 6, 48, 67, 66}; + toc_buffer[18] = {1, 7, 53, 49, 41}; + toc_buffer[19] = {1, 7, 53, 49, 6}; + toc_buffer[20] = {1, 7, 53, 49, 1}; + toc_buffer[21] = {1, 8, 54, 55, 0}; + toc_buffer[22] = {1, 8, 54, 55, 67}; + toc_buffer[23] = {1, 8, 54, 55, 53}; + toc_buffer[24] = {1, 9, 65, 18, 7}; + toc_buffer[25] = {1, 9, 65, 18, 1}; + toc_buffer[26] = {1, 9, 65, 18, 0}; + toc_buffer[27] = {1, 16, 66, 21, 55}; + toc_buffer[28] = {1, 16, 66, 21, 54}; + toc_buffer[29] = {1, 16, 66, 21, 8}; + toc_buffer[30] = {1, 17, 70, 37, 1}; + toc_buffer[31] = {1, 17, 70, 37, 0}; + toc_buffer[32] = {1, 17, 70, 37, 18}; + toc_buffer[33] = {1, 18, 71, 32, 65}; + toc_buffer[34] = {1, 18, 71, 32, 16}; + toc_buffer[35] = {1, 18, 71, 32, 1}; + toc_buffer[36] = {1, 19, 81, 54, 0}; + toc_buffer[37] = {1, 19, 81, 54, 21}; + toc_buffer[38] = {1, 19, 81, 54, 70}; + toc_buffer[39] = {1, 20, 82, 54, 17}; + toc_buffer[40] = {1, 20, 82, 54, 1}; + toc_buffer[41] = {1, 20, 82, 54, 0}; + toc_buffer[42] = {1, 21, 83, 69, 32}; + toc_buffer[43] = {1, 21, 83, 69, 71}; + toc_buffer[44] = {1, 21, 83, 69, 18}; + toc_buffer[45] = {1, 22, 86, 85, 1}; + toc_buffer[46] = {1, 22, 86, 85, 0}; + toc_buffer[47] = {1, 22, 86, 85, 54}; + toc_buffer[48] = {1, 23, 87, 5, 81}; + toc_buffer[49] = {1, 23, 87, 5, 20}; + toc_buffer[50] = {1, 23, 87, 5, 1}; + toc_buffer[51] = {1, 24, 89, 2, 0}; + toc_buffer[52] = {1, 24, 89, 2, 54}; + toc_buffer[53] = {1, 24, 89, 2, 83}; + toc_buffer[54] = {1, 25, 89, 37, 21}; + toc_buffer[55] = {1, 25, 89, 37, 1}; + toc_buffer[56] = {1, 25, 89, 37, 0}; + toc_buffer[57] = {1, 32, 96, 0, 85}; + toc_buffer[58] = {1, 32, 96, 0, 86}; + toc_buffer[59] = {1, 32, 96, 0, 22}; + toc_buffer[60] = {1, 33, 96, 34, 1}; + toc_buffer[61] = {1, 33, 96, 34, 0}; + toc_buffer[62] = {1, 33, 96, 34, 5}; + toc_buffer[63] = {1, 34, 96, 87, 87}; + toc_buffer[64] = {1, 34, 96, 87, 24}; + toc_buffer[65] = {1, 34, 96, 87, 1}; + toc_buffer[66] = {1, 160, 1, 0, 0}; + toc_buffer[67] = {1, 160, 1, 0, 2}; + toc_buffer[68] = {1, 160, 1, 0, 89}; + toc_buffer[69] = {1, 161, 34, 0, 25}; + toc_buffer[70] = {1, 161, 34, 0, 1}; + toc_buffer[71] = {1, 161, 34, 0, 0}; + toc_buffer[72] = {1, 162, 21, 34, 0}; + toc_buffer[73] = {1, 162, 21, 34, 96}; + toc_buffer[74] = {1, 162, 21, 34, 32}; + + toc_entry_count = 75; +} + int main(int argc, char **argv) { // Initialize Verilators variables Verilated::commandArgs(argc, argv); @@ -727,39 +808,19 @@ int main(int argc, char **argv) { f_cd_bin = fopen("images/Zelda's Adventure (Europe).bin", "rb"); break; case 6: - f_cd_bin = fopen("images/tetris.bin", "rb"); + f_cd_bin = fopen("images/audiocd.bin", "rb"); break; case 7: f_cd_bin = fopen("images/Flashback (Europe).bin", "rb"); break; case 8: - f_cd_bin = fopen("images/Earth Command (Germany).bin", "rb"); + f_cd_bin = fopen("images/Apprentice_USA_single.bin", "rb"); + prepare_apprentice_usa_toc(); break; } assert(f_cd_bin); - toc_buffer[0] = {1, 1, 0, 0, 0}; - toc_buffer[1] = {1, 1, 0, 0, 0}; - toc_buffer[2] = {1, 1, 0, 0, 0}; - toc_buffer[3] = {1, 2, 3, 38, 69}; - toc_buffer[4] = {1, 2, 3, 38, 69}; - toc_buffer[5] = {1, 2, 3, 38, 69}; - toc_buffer[6] = {1, 3, 7, 1, 96}; - toc_buffer[7] = {1, 3, 7, 1, 96}; - toc_buffer[8] = {1, 3, 7, 1, 96}; - toc_buffer[9] = {1, 4, 18, 16, 71}; - toc_buffer[10] = {1, 4, 18, 16, 71}; - toc_buffer[11] = {1, 4, 18, 16, 71}; - toc_buffer[12] = {1, 160, 1, 0, 0}; - toc_buffer[13] = {1, 160, 1, 0, 0}; - toc_buffer[14] = {1, 160, 1, 0, 0}; - toc_buffer[15] = {1, 161, 4, 0, 0}; - toc_buffer[16] = {1, 161, 4, 0, 0}; - toc_buffer[17] = {1, 161, 4, 0, 0}; - toc_buffer[18] = {1, 162, 0, 0, 0}; - toc_entry_count=19; - CDi machine(machineindex); while (status == 0) { diff --git a/sim2/sim_top.sh b/sim2/sim_top.sh index a3af866..34153e7 100755 --- a/sim2/sim_top.sh +++ b/sim2/sim_top.sh @@ -1,5 +1,5 @@ verilator --top-module emu \ - --trace --trace-fst --trace-structs --cc --assert --exe --timing --build \ + --trace --trace-fst --trace-structs --cc --assert --exe --build \ --build-jobs 8 sim_top.cpp -I../rtl \ ../rtl/*.sv ../CDi.sv ../rtl/*.v \ tg68kdotc_verilog_wrapper.v ur6805.v \