8302

Nagging hardware related question? Post here!
Derek_Stewart
Font of All Knowledge
Posts: 4653
Joined: Mon Dec 20, 2010 11:40 am
Location: Sunny Runcorn, Cheshire, UK

Re: 8302

Post by Derek_Stewart »

Hi,

I was wondering if a replacement for the 8302 could be produced, as the orginal chip is becoming hard to find.


Regards,

Derek
User avatar
Popopo
Gold Card
Posts: 367
Joined: Wed Apr 07, 2021 10:37 am

Re: 8302

Post by Popopo »

I have the same question than Derek.

Could it be possible to reproduce it same as we do a replacement like Hermes?
I would like to try openhardware replacement for IC22, IC23
IC24 already has replacement and the HAL for Iss6 if I am not wrong also exist everyone can make its own one.

Also I have another question,
Why we doesn't use the value of R103 and R102 original instead to place a 0 Ohms on them?
Instead of it, it was described to solder on IC23 the two resistors of 33K and attach the common node to -12v rail...
Why is that recomended instead use their already footprint R102 & R103 and mood the PCB (if necessary to attach the common node to -12v Rail?

Thank you a lot


User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: 8302

Post by bwinkel67 »

What is the MIST implementation of the 8302?

Code: Select all

//
// zx8302.v
//
// ZX8302 for Sinclair QL for the MiST
// https://github.com/mist-devel
// 
// Copyright (c) 2015 Till Harbaum <till@harbaum.org> 
// Copyright (c) 2021 Daniele Terdina
// 
// This source file is free software: 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 3 of the License, or 
// (at your option) any later version. 
// 
// This source 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 program.  If not, see <http://www.gnu.org/licenses/>. 
//

module zx8302 (
		input          clk,       // 21 mhz
		input          clk_sys,   // 27 MHz board clock
      input          reset,
      input          init,
		
		// interrupts
		output [1:0]   ipl,
		input          xint,
		
		// 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,
		output			mdv_active,

		output         led,
		output         audio,
		
		// vertical synv 
		input          vs,

		// joysticks
		input [4:0]    js0,
		input [4:0]    js1,
		
		input          ps2_kbd_clk,
		input          ps2_kbd_data,
		
      // bus interface
		input				clk_bus,
		input				cpu_sel,
		input				cpu_wr,
		input [1:0] 	cpu_addr,      // a[5,1]
		input				cpu_uds,
		input				cpu_lds,
		input [15:0]   cpu_din,
		output [15:0]  cpu_dout
		
);


// comdata shift register
wire ipc_comdata_in = comdata_reg[0];
reg [3:0] comdata_reg /* synthesis noprune */;
reg [1:0] ipc_busy;
reg comdata_to_cpu;
reg prev_ipc_comctrl;


// ---------------------------------------------------------------------------------
// ----------------------------- CPU register write --------------------------------
// ---------------------------------------------------------------------------------

reg [7:0] mctrl;

// cpu is writing io registers
always @(negedge clk_bus) begin
	if (reset) begin
		comdata_reg <= 4'b0000;
		ipc_busy <= 2'b11;
	end
	irq_ack <= 5'd0;
	
	// cpu writes to 0x18XXX area
	if(cpu_sel && cpu_wr) begin
		// even addresses have uds asserted and use the upper 8 data bus bits
		if(cpu_uds) begin
			// cpu writes microdrive control register
			if(cpu_addr == 2'b10)
				mctrl <= cpu_din[15:8];
		end

		// odd addresses have lds asserted and use the lower 8 data bus bits
		if(cpu_lds) begin
			// 18003 - IPCWR
			// (host sends a single bit to ipc)
			if(cpu_addr == 2'b01) begin
				// data is ----XEDS
				// S = start bit (should be 0)
				// D = data bit (0/1)
				// E = stop bit (should be 1)
            // X = extra stopbit (should be 1)
				comdata_reg <= cpu_din[3:0];
				ipc_busy <= 2'b11;		// Show IPC BUSY until the IPC asserts COMCTL twice
         end

			// cpu writes interrupt register
			if(cpu_addr == 2'b10) begin
				irq_mask <= cpu_din[7:5];
				irq_ack <= cpu_din[4:0];
			end
		end
	end
	if (!ipc_comctrl && prev_ipc_comctrl) begin
		comdata_to_cpu <= zx8302_comdata_in;	// Latch COMDATA since the IPC will quickly reset it to 1 when sending data
		comdata_reg <= { 1'b1, comdata_reg[3:1] };
		ipc_busy <= { 1'b0, ipc_busy[1] };
	end
	prev_ipc_comctrl <= ipc_comctrl;
end

// ---------------------------------------------------------------------------------
// ----------------------------- CPU register read ---------------------------------
// ---------------------------------------------------------------------------------

// status register read
// bit 0       Network port
// bit 1       Transmit buffer full
// bit 2       Receive buffer full
// bit 3       Microdrive GAP
// bit 4       SER1 DTR
// bit 5       SER2 CTS
// bit 6       IPC busy
// bit 7       COMDATA

wire [7:0] io_status = { comdata_to_cpu, ipc_busy[0], 2'b00,
		(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]:
	(cpu_addr == 2'b01)?rtc[31:16]:

	// 18020/18021 and 18022/18023
	(cpu_addr == 2'b10)?{io_status, irq_pending}:
	(cpu_addr == 2'b11)?(mdv_seldrive?{mdv2_byte, mdv2_byte}:{mdv_byte, mdv_byte}):

	16'h0000;	

// ---------------------------------------------------------------------------------
// -------------------------------------- IPC --------------------------------------
// ---------------------------------------------------------------------------------
	
wire ipc_comctrl;
wire ipc_comdata_out;

// 8302 sees its own comdata as well as the one from the ipc
wire zx8302_comdata_in = ipc_comdata_in && ipc_comdata_out;



wire [1:0] ipc_ipl;

ipc ipc (	
	.reset    	    ( reset          ),
	.clk_sys        ( clk_sys        ),   // 27 MHz board clock

	.comctrl        ( ipc_comctrl    ),
	.comdata_in     ( ipc_comdata_in ),
	.comdata_out    ( ipc_comdata_out),

   .audio          ( audio          ),
	.ipl            ( ipc_ipl        ),

	.js0            ( js0            ),
	.js1            ( js1            ),
	
	.ps2_kbd_clk    ( ps2_kbd_clk    ),
	.ps2_kbd_data   ( ps2_kbd_data   )
);

// ---------------------------------------------------------------------------------
// -------------------------------------- IRQs -------------------------------------
// ---------------------------------------------------------------------------------

wire [7:0] irq_pending = {1'b0, (mdv_sel == 0), clk64k, xint_irq, vsync_irq, 1'b0, 1'b0, gap_irq };
reg [2:0] irq_mask;
reg [4:0] irq_ack;

// any pending irq raises ipl to 2 and the ipc can control both ipl lines
assign ipl = { ipc_ipl[1] && (irq_pending[4:0] == 0), ipc_ipl[0] };

// vsync irq is set whenever vsync rises
reg vsync_irq;
wire vsync_irq_reset = reset || irq_ack[3];
always @(posedge clk) begin
	reg old_vs;
	
	old_vs <= vs;
	if(vsync_irq_reset)   vsync_irq <= 1'b0;
	else if(~old_vs & vs) vsync_irq <= 1'b1;
end

// toggling the mask will also trigger irqs ...
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 clk) begin
	reg old_irq;
	
	old_irq <= gap_irq_in;
	if(gap_irq_reset)              gap_irq <= 1'b0;
	else if(~old_irq & gap_irq_in) gap_irq <= 1'b1;
end

// toggling the mask will also trigger irqs ...
wire xint_irq_in = xint && irq_mask[2];
reg xint_irq;
wire xint_irq_reset = reset || irq_ack[4];
always @(posedge clk) begin
	reg old_irq;
	
	old_irq <= xint_irq_in;
	if(xint_irq_reset)              xint_irq <= 1'b0;
	else if(~old_irq & xint_irq_in) xint_irq <= 1'b1;
end


// ---------------------------------------------------------------------------------
// ----------------------------------- microdrive ----------------------------------
// ---------------------------------------------------------------------------------

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] || mdv_sel[1]);

mdv mdv (
   .clk      ( clk          ),
	.reset    ( init         ),
	
   .mdv_drive (1),		//This is MDV1_
   
	.sel      ( mdv_sel[0]   ),

   // control bits	
	.gap      ( mdv_gap      ),
	.tx_empty ( mdv_tx_empty ),
	.rx_ready ( mdv_rx_ready ),
	.dout     ( mdv_byte     ),
	
	.download ( mdv_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 ( mdv_addr     ),
	.mem_read ( mdv_read     ),  
	.mem_din  ( mdv_din      )	
);

mdv mdv2 (
   .clk      ( clk          ),
	.reset    ( init         ),
   
   .mdv_drive ( 2 ),		//This is MDV2_
	
   .sel      ( mdv_sel[1]   ),

   // 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 @(posedge clk) begin
	reg old_mctrl;
	
	old_mctrl <= mctrl[1];
	if(old_mctrl & ~mctrl[1]) mdv_sel <= { mdv_sel[6:0], mctrl[0] };
end

// 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;
assign mdv_active = mdv_sel[1] || mdv_sel[0];

// ---------------------------------------------------------------------------------
// -------------------------------------- RTC --------------------------------------
// ---------------------------------------------------------------------------------

// PLL for the real time clock (rtc)
reg [47:0] rtc;
always @(posedge clk64k)
	rtc <= rtc + 48'd1;

wire clk64k;
pll_rtc pll_rtc (
	 .inclk0(clk_sys),
	 .c0(clk64k)           // 65536Hz
);

	
endmodule
Source https://github.com/mist-devel/ql/tree/master


User avatar
Popopo
Gold Card
Posts: 367
Joined: Wed Apr 07, 2021 10:37 am

Re: 8302

Post by Popopo »

bwinkel67 wrote: Thu Jun 13, 2024 7:36 pm What is the MIST implementation of the 8302?

Code: Select all

//
// zx8302.v
	...
endmodule
Source https://github.com/mist-devel/ql/tree/master
Wau! amazing!
Thank you, the code looks pretty good for understanding.
I 'm going to study it.

Edit: it says MDVs emulation (QLay format), what does it mean?
Whatever it is a good point to start :) thanks


Derek_Stewart
Font of All Knowledge
Posts: 4653
Joined: Mon Dec 20, 2010 11:40 am
Location: Sunny Runcorn, Cheshire, UK

Re: 8302

Post by Derek_Stewart »

... so just need to interface a FPGA to ths QL 8302 socket.


Regards,

Derek
User avatar
Pr0f
QL Wafer Drive
Posts: 1542
Joined: Thu Oct 12, 2017 9:54 am

Re: 8302

Post by Pr0f »

The code in the mister FPGA does just enough to 'mimic' a Microdrive interface, and provide a rudimentary seconds counter RTC, but don't be fooled - there is a lot that's not supported here - not sure if the QL network interface is implemented in the mister hardware? Certainly the serial port (transmit side) is not implemented, nor all the timing logic for the Microdrives themselves


User avatar
bwinkel67
QL Wafer Drive
Posts: 1511
Joined: Thu Oct 03, 2019 2:09 am

Re: 8302

Post by bwinkel67 »

Yeah, I figured as much when it talked about emulated MDV images. But it may be a start for someone that has the skill set. Plus, maybe Charlie has some insights regarding the MDV stuff since he did recreate the Spectrum's Interface 1 ULA. Could this also be done the PiStorm approach via a CPLD/RaPi model so the 8302 implementation is more at a software level?


Post Reply