diff --git a/cores/ql/data_io.v b/cores/ql/data_io.v index 5b36ec4..d7dd364 100644 --- a/cores/ql/data_io.v +++ b/cores/ql/data_io.v @@ -83,7 +83,9 @@ always@(posedge sck, posedge ss) begin if(sdi) begin // download rom to address 0, microdrive image to 16MB+ if(index == 0) laddr <= 25'h0 - 25'd1; - else laddr <= 25'h800000 - 25'd1; + if(index == 1) laddr <= 25'h800000 - 25'd1; //mdv1_ + if(index == 2) laddr <= 25'h900000 - 25'd1; //mdv2_ + if(index == 3) laddr <= 25'h0 - 25'd1; //Additional ROM bios selection downloading_reg <= 1'b1; end else diff --git a/cores/ql/mdv.v b/cores/ql/mdv.v index 35bad04..cb8c7a9 100644 --- a/cores/ql/mdv.v +++ b/cores/ql/mdv.v @@ -25,8 +25,10 @@ module mdv ( input reset, input reverse, - - input sel, + + input mdv_drive, + + input sel, // select microdrive 1 or 2 // control bits output gap, @@ -46,8 +48,9 @@ module mdv ( input [15:0] mem_din ); -localparam BASE_ADDR = 25'h800000; - +// mdv1_ image stored at h800000, mdv2_ image stored at address h900000 +wire [24:0] BASE_ADDR = (mdv_drive == 1)?25'h800000:25'h900000; + // a gap is permanently present if no mdv is inserted or if // there's a gap on the inserted one. This is the signal that triggers // the irq and can be seen by the cpu @@ -118,7 +121,7 @@ always @(posedge mdv_clk) begin mdv_bit_cnt <= mdv_bit_cnt + 4'd1; if(mdv_bit_cnt == 15) begin mdv_data <= mdv_din; - mdv_data_valid <= !mdv_gap_active && + mdv_data_valid <= !mdv_gap_active && // don't generate data_valid for first 12 bytes (preamble) (mdv_gap_cnt > 5) && // and also not for the sector internal preamble @@ -126,8 +129,9 @@ always @(posedge mdv_clk) begin mdv_next_word <= 1'b1; - // reset counters when address is out of range - if((mem_addr > mdv_end)||(mem_addr < 25'h800000)) begin + // reset counters when address is out of range + if((mem_addr > mdv_end)||(mem_addr < BASE_ADDR)) begin + mem_addr <= BASE_ADDR; // assume we start at the end of a post-sector/pre-header gap diff --git a/cores/ql/ql.v b/cores/ql/ql.v index 7c75f68..77c761b 100644 --- a/cores/ql/ql.v +++ b/cores/ql/ql.v @@ -70,7 +70,9 @@ module ql ( // it to control the menu on the OSD parameter CONF_STR = { "QL;;", - "F1,MDV;", + "F,MDV,Load MDV1;", + "F,MDV,Load MDV2;", + "F,ROM;", "O2,MDV direction,normal,reverse;", "O3,RAM,128k,640k;", "O4,Video mode,PAL,NTSC;", @@ -78,7 +80,7 @@ parameter CONF_STR = { "T6,Reset" }; -parameter CONF_STR_LEN = 4+7+32+17+23+20+8; +parameter CONF_STR_LEN = 4+16+16+6+32+17+23+20+8; // the status register is controlled by the on screen display (OSD) wire [7:0] status; @@ -206,8 +208,10 @@ wire sys_wr = dio_download?dio_write:(cpu_wr && cpu_ram); wire sys_oe = dio_download?1'b0:(cpu_rd && cpu_mem); // microdrive emulation and video share the video cycle time slot -wire [24:0] video_cycle_addr = mdv_read?mdv_addr:{6'd0, video_addr}; -wire video_cycle_rd = mdv_read?1'b1:video_rd; +// only one drive at a time is accessed +wire [24:0] video_cycle_addr = (mdv_read || mdv2_read)?(mdv_seldrive?mdv2_addr:mdv_addr):{6'd0, video_addr}; +wire video_cycle_rd = (mdv_read || mdv2_read)?1'b1:video_rd; + // video and CPU/data_io time share the sdram bus wire [24:0] sdram_addr = video_cycle?video_cycle_addr:sys_addr; @@ -352,7 +356,7 @@ osd #(12,0,5) osd ( // -------------------------------------- reset ------------------------------------ // --------------------------------------------------------------------------------- -wire rom_download = dio_download && (dio_index == 0); +wire rom_download = dio_download && (dio_index == 0 || dio_index == 3); reg [11:0] reset_cnt; wire reset = (reset_cnt != 0); always @(posedge clk2) begin @@ -370,10 +374,15 @@ wire zx8302_sel = cpu_cycle && cpu_io && !cpu_addr[6]; wire [1:0] zx8302_addr = {cpu_addr[5], cpu_addr[1]}; wire [15:0] zx8302_dout; -wire mdv_download = (dio_index == 1) && dio_download; -wire mdv_men; +wire mdv_download = (dio_index == 1) && dio_download; //signal for active download from SD +wire mdv2_download = (dio_index == 2) && dio_download; //signal for active download from SD +wire mdv_men; //signal telling mdv emulation that it may use the video wire mdv_read; +wire mdv2_read; wire [24:0] mdv_addr; +wire [24:0] mdv2_addr; +wire mdv_seldrive; //1 for MDV2_ active, 0 for MDV1_ active or nothing + wire audio; assign AUDIO_L = audio; @@ -397,7 +406,7 @@ zx8302 zx8302 ( .cpu_addr ( zx8302_addr ), .cpu_ds ( cpu_ds ), .cpu_din ( cpu_dout ), - .cpu_dout ( zx8302_dout ), + .cpu_dout ( zx8302_dout ), // joysticks .js0 ( js0[4:0] ), @@ -410,15 +419,22 @@ zx8302 zx8302 ( // microdrive sdram interface .mdv_addr ( mdv_addr ), + .mdv2_addr ( mdv2_addr ), .mdv_din ( sdram_dout ), .mdv_read ( mdv_read ), + .mdv2_read ( mdv2_read ), .mdv_men ( mdv_men ), .video_cycle ( video_cycle ), .mdv_reverse ( status[2] ), .mdv_download ( mdv_download ), + .mdv2_download ( mdv2_download ), + + .mdv_seldrive ( mdv_seldrive) , + .mdv_dl_addr ( dio_addr ) + ); // --------------------------------------------------------------------------------- diff --git a/cores/ql/zx8302.v b/cores/ql/zx8302.v index 86ac1fb..9b6e0e9 100644 --- a/cores/ql/zx8302.v +++ b/cores/ql/zx8302.v @@ -32,14 +32,19 @@ module zx8302 ( // sdram interface for microdrive emulation output [24:0] mdv_addr, + output [24:0] mdv2_addr, input [15:0] mdv_din, output mdv_read, + output mdv2_read, input mdv_men, input video_cycle, // interface to watch MDV cartridge upload input [24:0] mdv_dl_addr, input mdv_download, + input mdv2_download, + + output mdv_seldrive, input mdv_reverse, output led, @@ -127,8 +132,10 @@ end // bit 7 COMDATA wire [7:0] io_status = { zx8302_comdata_in, ipc_busy, 2'b00, - mdv_gap, mdv_rx_ready, mdv_tx_empty, 1'b0 }; - + (mdv_seldrive?mdv2_gap:mdv_gap), + (mdv_seldrive?mdv2_rx_ready:mdv_rx_ready), + (mdv_seldrive?mdv2_tx_empty:mdv_tx_empty), 1'b0 }; + assign cpu_dout = // 18000/18001 and 18002/18003 (cpu_addr == 2'b00)?rtc[47:32]: @@ -136,7 +143,7 @@ assign cpu_dout = // 18020/18021 and 18022/18023 (cpu_addr == 2'b10)?{io_status, irq_pending}: - (cpu_addr == 2'b11)?{mdv_byte, mdv_byte}: + (cpu_addr == 2'b11)?(mdv_seldrive?{mdv2_byte, mdv2_byte}:{mdv_byte, mdv_byte}): 16'h0000; @@ -213,7 +220,7 @@ always @(posedge vs or posedge vsync_irq_reset) begin end // toggling the mask will also trigger irqs ... -wire gap_irq_in = mdv_gap && irq_mask[0]; +wire gap_irq_in = (mdv_seldrive?mdv2_gap:mdv_gap) && irq_mask[0]; reg gap_irq; wire gap_irq_reset = reset || irq_ack[0]; always @(posedge gap_irq_in or posedge gap_irq_reset) begin @@ -236,16 +243,22 @@ end // --------------------------------------------------------------------------------- wire mdv_gap; +wire mdv2_gap; wire mdv_tx_empty; +wire mdv2_tx_empty; wire mdv_rx_ready; +wire mdv2_rx_ready; wire [7:0] mdv_byte; +wire [7:0] mdv2_byte; -assign led = !mdv_sel[0]; +assign led = !(mdv_sel[0] || mdv_sel[1]); mdv mdv ( .clk ( clk ), .reset ( init ), + .mdv_drive (1), //This is MDV1_ + .sel ( mdv_sel[0] ), .reverse ( mdv_reverse ), @@ -268,12 +281,47 @@ mdv mdv ( .mem_din ( mdv_din ) ); +mdv mdv2 ( + .clk ( clk ), + .reset ( init ), + + .mdv_drive ( 2 ), //This is MDV2_ + + .sel ( mdv_sel[1] ), + + .reverse ( mdv_reverse ), + + // control bits + .gap ( mdv2_gap ), + .tx_empty ( mdv2_tx_empty ), + .rx_ready ( mdv2_rx_ready ), + .dout ( mdv2_byte ), + + .download ( mdv2_download ), + .dl_addr ( mdv_dl_addr ), + + // ram interface to read image + .mem_ena ( mdv_men ), + .mem_cycle( video_cycle ), + .mem_clk ( clk_bus ), + .mem_addr ( mdv2_addr ), + .mem_read ( mdv2_read ), + + .mem_din ( mdv_din ) +); + // the microdrive control register mctrl generates the drive selection +// mdv_sel = 1 for mdv1_, mdv_sel = 2 for mdv2_ reg [7:0] mdv_sel; always @(negedge mctrl[1]) mdv_sel <= { mdv_sel[6:0], mctrl[0] }; +// 0 for MDV1_ or nothing and 1 for MDV2_ +// Only one microdrive can be accessed at a time, this allows +// switching between them. +assign mdv_seldrive = mdv_sel[1]?1'b1:1'b0; + // --------------------------------------------------------------------------------- // -------------------------------------- RTC -------------------------------------- // ---------------------------------------------------------------------------------