Help - Implementing Shadow RAM in CPLD

discuss both original and modern hardware for the bbc micro/electron
User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Sat Nov 28, 2020 8:03 pm

KenLowe wrote:
Sat Nov 28, 2020 7:42 pm
The datasheet states that during a write operation, 'the trailing edge of DS causes the device to latch the written data', and if I'm reading the data sheet correctly I need a minimum 10ns between RTC_DS falling and RnW rising (tRWH) in order to correctly latch in the data? If the 6502 RnW signal typically lags the falling edge of Phi2 by about 50ns, the timing seems quite marginal, or is that quite normal? I will check that on the scope shortly.
It's quite normal for hold time margins to be quite small.

As long as the hold time specification is met, then I would say the problem is elsewhere.
KenLowe wrote:
Sat Nov 28, 2020 7:42 pm
I was also toying with the idea of adding a couple of inverters into the RTC RnW line to see if the extra propagation delay would make any difference. However, that would take a little bit of effort, so wanted to first check if it's a worthwhile exercise, or if I'd just be wasting my time?
I would say it's only worth doing this I this if the scope shows an actual problem with the timing.

But then again, none of the other timings during the write looked tight either.

Can I just check, all this is happening on the surface mount version of the PCB (i.e. the CPLD is no longer dangling off a set of dupont cables)?

Dave

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Sat Nov 28, 2020 8:25 pm

What's the power supply voltage (VCC), measured close to the RTC chip?

My only other thought was whether permenantly grounding CS might be an issue. Is this something that worked on the dev board?

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Nov 28, 2020 8:35 pm

hoglet wrote:
Sat Nov 28, 2020 8:03 pm
KenLowe wrote:
Sat Nov 28, 2020 7:42 pm
The datasheet states that during a write operation, 'the trailing edge of DS causes the device to latch the written data', and if I'm reading the data sheet correctly I need a minimum 10ns between RTC_DS falling and RnW rising (tRWH) in order to correctly latch in the data? If the 6502 RnW signal typically lags the falling edge of Phi2 by about 50ns, the timing seems quite marginal, or is that quite normal? I will check that on the scope shortly.
It's quite normal for hold time margins to be quite small.

As long as the hold time specification is met, then I would say the problem is elsewhere.
Thanks. That helps a lot. I've just grabbed some more samples of a write operation, and they actually look very good. On these traces, the falling edge of RTC_AS and RTC_DS is nearly always one sample prior to the rising edge of RnW.
hoglet wrote:
Sat Nov 28, 2020 8:03 pm
KenLowe wrote:
Sat Nov 28, 2020 7:42 pm
I was also toying with the idea of adding a couple of inverters into the RTC RnW line to see if the extra propagation delay would make any difference. However, that would take a little bit of effort, so wanted to first check if it's a worthwhile exercise, or if I'd just be wasting my time?
I would say it's only worth doing this I this if the scope shows an actual problem with the timing.
This is possibly a bit more difficult than I initially anticipated. From the logic analyser, I can see that I'm getting a lot of spurious RTC_AS and RTC_DS spikes (due to addresses FE38 & FE3C appearing briefly on the address bus when the address is changing), so triggering is happening way too early. I'm not sure how easy it is to deal with that on the scope!
hoglet wrote:
Sat Nov 28, 2020 8:03 pm
Can I just check, all this is happening on the surface mount version of the PCB (i.e. the CPLD is no longer dangling off a set of dupont cables)?
That's correct. I'm testing this on my V2 board that has the CPLD, RAM and RTC all soldered directly onto the board. All are SMD components.
...however, I cut the 8 data tracks between the data buffer and the RAM & RTC the other day when I was testing theory about series resistors. I don't have these series resistors installed any longer. However, I'm now using a separate data buffer soldered onto a bit of vero board to drive the RAM & RTC data bus. I have dupont wires running from a CPU breakout board to the data buffer, and a further set of dupont wires running from the data buffer to a 28 pin ROM socket that is on the RTC / RAM side of the cut that I made to the traces. I'm confident this is working fine as I'm able to read from and write to the RAM without any issue. This arrangement has also allowed me to change from 47k pull down to 4k7 on this section of the data bus. It also allows me to easily switch between pull down and pull up.

I do also have a second V2 board without any cuts, but it's got 47k pull down on the data bus, and I thought that may be causing issues, which is why I'm currently not using that board. The RTC is not working on that board either. I could switch to that board if you think it would help.

Oddly, on my dev board where the CPLD is dangling off a set of dupont cables, I have a DIP version of the DS12885 plugged into a small carrier board that then plugs into one of my older IntegraB boards. That one works flawlessly (having fixed the earlier battery issue).
Last edited by KenLowe on Sat Nov 28, 2020 8:45 pm, edited 1 time in total.

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Nov 28, 2020 8:43 pm

hoglet wrote:
Sat Nov 28, 2020 8:25 pm
What's the power supply voltage (VCC), measured close to the RTC chip?
4.97v between pins 12 (Gnd) and 24 (Vcc), and 3.77v between pins 12 (Gnd) and 20 (VBat).
hoglet wrote:
Sat Nov 28, 2020 8:25 pm
My only other thought was whether permanently grounding CS might be an issue. Is this something that worked on the dev board?
It's always been that way with all versions of IntegraB boards. And, yes with the DIP version of the DS12885 it's working fine on my dev board setup with CS grounded.

The odd thing is I've got another DS12885 SMD RTC soldered onto a small carrier board, and if I hook that into this V2 board (with dupont patch wires), I can get that one to work just fine. To disable the onboard RTC, I just stop pulsing the AD and DS lines (I use other temporary lines from the CPLD for this remote RTC).
Last edited by KenLowe on Sat Nov 28, 2020 8:56 pm, edited 1 time in total.

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Sat Nov 28, 2020 8:55 pm

KenLowe wrote:
Sat Nov 28, 2020 8:35 pm
This is possibly a bit more difficult than I initially anticipated. From the logic analyser, I can see that I'm getting a lot of spurious RTC_AS and RTC_DS spikes (due to addresses FE38 & FE3C appearing briefly on the address bus when the address is changing), so triggering is happening way too early. I'm not sure how easy it is to deal with that on the scope!
OK, that's a bit unexpected.

The point of ANDing RTC_AS/DS with Phi2 in the CPLD is to ensure they are be asserted when the address bus is stable, to elimimate glitches.

(The address bus will only change when Phi2 is low)

If you are seeing glitches on RTC_AS/DS, then it's worth investigating further.

I would go back to the scope and put Phi2 on one channel and RTC_AS or RTC_DS on the other, and try to capture some good scope plots of the glitches.

Dave

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Nov 28, 2020 9:22 pm

It may just be the logic analyser that's doing funny things. Everything to the right of the trace, where it's shaded is fine. The bit to the left is where I'm getting both AS and DS pulsing at the same time. That just shouldn't be happening. I'm also not sure why I'm getting sections of blank data. I'm guessing data's not getting transferred over to the PC quickly enough.

I set the logic analyser running with a trigger on either the AS or DS. I then run a bit of basic code on the beeb that assembles a short piece of code, and then automatically calls that code. The code just repeatedly writes &55 then &AA to RTC address &20.
RTC-Capture9.PNG
Odd behaviour with AS and DS
And here's a zoomed in view of the shaded area:
RTC-Capture10.PNG
...and then it's fine once it settles out.
Edit: Ah, those blank areas are where the IntegraB data bus is doing nothing. However, the beeb will be doing stuff!

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Nov 28, 2020 9:31 pm

And here's one of the sections where it's glitchy. Note that Phi2, AS & DS are all temporary outputs from the CPLD. It would be interesting to know if the CPLD is genuinely spitting out those signals, or if the logic analyser is wrongly picking these up:
RTC-Capture11.PNG
Glitchy Phi2, AS & DS
And for reference, here's the CPLD code that's currently running on that machine:

Code: Select all

`timescale 1ns / 1ps
/************************************************************************
	 IntegraBV2.v

	 IntegraB V2 - A fully expanded ROM / RAM Board for BBC Micro
	 Revision 01 - November 2020
    Copyright (C) 2020 Ken Lowe

    IntegraBV2 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 program 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/>.

	 Email: ken@skidog.co.uk

************************************************************************/
module IntegraBV2(
	input from_CPU_RnW,
	input from_CPU_Phi1,
	input from_CPU_Phi2, //Temporary input
	input from_CPU_dPhi2,
	input bbc_nRST,
	input [7:0] bbc_DATA,
	input [15:0] bbc_ADDRESS,
	input [15:0] RamWriteProt,
	input [15:8] IntegraRomSel,
	input [3:0] BeebRomSel,

	output to_bbc_Phi1,
	output to_bbc_RnW,
	output to_bbc_rD0,
	output to_bbc_rD1,
	output nDBuf_CE,
	output nDBuf_Dir,
	output nWDS,
	output nRDS,
	output nRomBankSel0_3,
	output [15:8] nRomBankSel,
	output RTC_AS,
	output RTC_DS,
	output RAM_CE,
	output [18:14] Ram_ADDRESS
	);


	// Repeat RnW & Phi1 from Input to Output
	wire	 Phi1;
	wire	 Phi2;
	wire	 ShAct;
	wire	 RnW;
	assign Phi1			 = from_CPU_Phi1;
	assign Phi2			 = from_CPU_Phi2;
	assign RnW			 = from_CPU_RnW;
	assign to_bbc_Phi1 = !(!Phi1 & !ShAct);
	assign to_bbc_RnW  = !(!RnW  & !ShAct);
	// assign nDBuf_Dir	 = RnW;
	assign nDBuf_Dir	 = 1'b0; // temporary force direction so CPLD can see data. Logic 0: CPU -> IntegraB

	// Address decoding. Note that the lowest 2 bits A0 and A1 are not used.
	wire   FE3x		= (bbc_ADDRESS[15:4] == 12'hFE3);
	wire	 FE30_7  = FE3x && (bbc_ADDRESS[3] == 1'b0);
	wire   FE30_3  = FE3x && (bbc_ADDRESS[3:2] == 2'b00);
	wire   FE34_7  = FE3x && (bbc_ADDRESS[3:2] == 2'b01);
	
	// nWDS is normally just !( RnW & !Phi1) but we check for Write protect and hold nWDS high is Write Protect is active.
	// nWDS needs to consider all 16 RAM banks AND the Shadow Bank
	wire	 ShadowSel;
	wire   RamBankSel[15:0];
	wire	 GenBankSel[15:0];
	assign nRDS = !( RnW & Phi2);
	// assign nWDS =   !((!RnW & Phi2 & GenBankSel[10] & !RamWriteProt[10])
	// 				|     (!RnW & Phi2 & GenBankSel[11] & !RamWriteProt[11])
	// 				|     (!RnW & Phi2 & GenBankSel[12] & !RamWriteProt[12])
	// 				|     (!RnW & Phi2 & GenBankSel[13] & !RamWriteProt[13])
	// 				|     (!RnW & Phi2 & GenBankSel[14] & !RamWriteProt[14])
	// 				|     (!RnW & Phi2 & GenBankSel[15] & !RamWriteProt[15])
	// 				|     (!RnW & Phi2 & ShadowSel));
	
	assign nWDS = !((!RnW & Phi2 & !RamBankSel[0]  & !RamWriteProt[0]  & !BeebRomSel[0])
					|   (!RnW & Phi2 & !RamBankSel[1]  & !RamWriteProt[1]  & !BeebRomSel[1])
					|   (!RnW & Phi2 & !RamBankSel[2]  & !RamWriteProt[2]  & !BeebRomSel[2])
					|   (!RnW & Phi2 & !RamBankSel[3]  & !RamWriteProt[3]  & !BeebRomSel[3])
					|	 (!RnW & Phi2 & !RamBankSel[4]  & !RamWriteProt[4])
					|   (!RnW & Phi2 & !RamBankSel[5]  & !RamWriteProt[5])
					|   (!RnW & Phi2 & !RamBankSel[6]  & !RamWriteProt[6])
					|   (!RnW & Phi2 & !RamBankSel[7]  & !RamWriteProt[7])
					|   (!RnW & Phi2 & !RamBankSel[8]  & !RamWriteProt[8]  & !IntegraRomSel[8])
					|   (!RnW & Phi2 & !RamBankSel[9]  & !RamWriteProt[9]  & !IntegraRomSel[9])
					|   (!RnW & Phi2 & !RamBankSel[10] & !RamWriteProt[10] & !IntegraRomSel[10])
					|   (!RnW & Phi2 & !RamBankSel[11] & !RamWriteProt[11] & !IntegraRomSel[11])
					|   (!RnW & Phi2 & !RamBankSel[12] & !RamWriteProt[12] & !IntegraRomSel[12])
					|   (!RnW & Phi2 & !RamBankSel[13] & !RamWriteProt[13] & !IntegraRomSel[13])
					|   (!RnW & Phi2 & !RamBankSel[14] & !RamWriteProt[14] & !IntegraRomSel[14])
					|   (!RnW & Phi2 & !RamBankSel[15] & !RamWriteProt[15] & !IntegraRomSel[15])
					|   (!RnW & Phi2 &  ShadowSel));

	// This logic sets PrvAct to logic state '1' if the addresses in the Private memory range &8000..&AFFF and if one of the Private Memory flags is active. 
	reg	 PrvEn;
	reg	 PrvS8;
	reg	 PrvS4;
	reg	 PrvS1;
	assign PrvAct    =   ((bbc_ADDRESS[15:12] == 4'h8) & (bbc_ADDRESS[11:10] == 2'b00) & PrvS1 & PrvEn  //address decodes to &8000..&83FF. Maps to &0000..&03FF in Shadow RAM
						  |    (bbc_ADDRESS[15:12] == 4'h8) &  PrvS4 & PrvEn   										 //address decodes to &8000..&8FFF. Maps to &0000..&0FFF in Shadow RAM
						  |    (bbc_ADDRESS[15:12] == 4'h9) &  PrvS8 & PrvEn											 //address decodes to &9000..&9FFF. Maps to &1000..&1FFF in Shadow RAM
						  |    (bbc_ADDRESS[15:12] == 4'hA) &  PrvS8 & PrvEn);										 //address decodes to &A000..&AFFF. Maps to &2000..&2FFF in Shadow RAM

	// This logic sets ShAct to logic state '1' if the addresses in the screen range &3000..&7FFF and if Shadow Memory is active. 
	reg	 ShEn;
	reg	 MemSel;
	wire	 ScreenMem =  ((bbc_ADDRESS[15:12] == 4'h3)    //address decodes to &3000..&3FFF
						  |   (bbc_ADDRESS[15:14] == 2'b01)); //address decodes to &4000..&7FFF
	assign ShAct     = ScreenMem & ShEn & !MemSel;

	// ShadowSel is logic '1' when either Shadow or Private RAM is being accessed. 
	// Note that Shadow and Private memory is mapped to a 32k Block of RAM as follows:
	// Function			BBC Memory	32K RAM
	//	Screen memory	3000..7FFF	3000..7FFF
	//	Private Prv1	8000..83FF	0000..03FF
	// Private Prv4	8000..8FFF	0000..0FFF
	// Private Prv8	9000..AFFF	1000..2FFF
	assign ShadowSel = !(!ShAct & !PrvAct);

	
	// The following logic is used to demux the ROM banks.
	// Banks 0..3 are located on the Beeb mainboard. These banks can be switched out for SWRAM on the IntegraB board instead
	// Banks 4..7 are SWRAM banks located on the IntegraB board
	// Banks 8..15 are ROM slots on the IntegraB board. These banks can be switched out for SWRAM on the IntegraB board instead
	// All SWRAM can be write protected in 16k banks.
	reg	 rD0;
	reg	 rD1;
	reg	 rD2;
	reg	 rD3;
	wire	 ROMDec;
	assign to_bbc_rD0 = rD0;
	assign to_bbc_rD1 = rD1;

	// If address is in range &8000..&BFFF then SWRAddr = 1, otherwise 0
	wire	 SWRAddr  =  (bbc_ADDRESS[15:14] == 2'b10);

	// Check if address is in the range &8000..&BFFF and it's not Private RAM that's being accessed.
	// assign ROMDec   = SWRAddr & !PrvAct;
	assign ROMDec   =  (SWRAddr & !PrvAct & Phi2
						 |	  SWRAddr & !PrvAct & !nRomBankSel0_3);


	// GenBankSel[x] is logic '1' when bank is selected
	// wire	 GenBankSel[15:0];
	assign GenBankSel[0]   = !rD3 & !rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[1]   = !rD3 & !rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[2]   = !rD3 & !rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[3]   = !rD3 & !rD2 &  rD1 &  rD0 & ROMDec;
	assign GenBankSel[4]   = !rD3 &  rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[5]   = !rD3 &  rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[6]   = !rD3 &  rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[7]   = !rD3 &  rD2 &  rD1 &  rD0 & ROMDec;
	assign GenBankSel[8]   =  rD3 & !rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[9]   =  rD3 & !rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[10]  =  rD3 & !rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[11]  =  rD3 & !rD2 &  rD1 &  rD0 & ROMDec;
	assign GenBankSel[12]  =  rD3 &  rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[13]  =  rD3 &  rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[14]  =  rD3 &  rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[15]  =  rD3 &  rD2 &  rD1 &  rD0 & ROMDec;
	

	// Logic to select Motherboard ROM Banks 0..3
	// Check if bank is mapped to ROM on beeb motherboard, or to RAM on IntegraB board
	// GenBankSel[x] is the output of the 4..16 line decoder. Logic '1' if output is decoded
	//	BeebRomSel[x] is based on jumper selection via pull up resistor. Logic '1' selects motherboard ROM. Logic '0' selects onboard RAM
	// nRomBankSelB[x] is logic '0' when bank is selected
	wire   nRomBankSelB[3:0];
	assign nRomBankSelB[0] = !(GenBankSel[0] & BeebRomSel[0]);
	assign nRomBankSelB[1] = !(GenBankSel[1] & BeebRomSel[1]);
	assign nRomBankSelB[2] = !(GenBankSel[2] & BeebRomSel[2]);
	assign nRomBankSelB[3] = !(GenBankSel[3] & BeebRomSel[3]);
	assign nRomBankSel0_3  = nRomBankSelB[0] & nRomBankSelB[1] & nRomBankSelB[2] & nRomBankSelB[3];

	// Logic to select IntegraB ROM Banks 8..15
	// Check if bank is mapped to ROM on IntegraB board, or to RAM on IntegraB board
	// GenBankSel[x] is the output of the 4..16 line decoder. Logic '1' if output is decoded
	//	IntegraRomSel[x] is based on jumper selection via pull up resistor. Logic '1' selects motherboard ROM. Logic '0' selects onboard RAM
	// nRomBankSel[x] is logic '0' when bank is selected otherwire open collector
	// assign nRomBankSel[8]  =  (GenBankSel[8]  & IntegraRomSel[8])  ? 1'b0 : 1'bz;
	// assign nRomBankSel[9]  =  (GenBankSel[9]  & IntegraRomSel[9])  ? 1'b0 : 1'bz;
	// assign nRomBankSel[10] =  (GenBankSel[10] & IntegraRomSel[10]) ? 1'b0 : 1'bz;
	// assign nRomBankSel[11] =  (GenBankSel[11] & IntegraRomSel[11]) ? 1'b0 : 1'bz;
	// assign nRomBankSel[12] =  (GenBankSel[12] & IntegraRomSel[12]) ? 1'b0 : 1'bz;
	// assign nRomBankSel[13] =  (GenBankSel[13] & IntegraRomSel[13]) ? 1'b0 : 1'bz;
	// assign nRomBankSel[14] =  (GenBankSel[14] & IntegraRomSel[14]) ? 1'b0 : 1'bz;
	// assign nRomBankSel[15] =  (GenBankSel[15] & IntegraRomSel[15]) ? 1'b0 : 1'bz;


	// assign nRomBankSel[9]	= 	 !ShadowSel ? 1'bz : 1'b0;
	// assign nRomBankSel[11]  =   (!GenBankSel[10] & !GenBankSel[11]) ? 1'bz : 1'b0;
	// assign nRomBankSel[13]  =   (!GenBankSel[12] & !GenBankSel[13]) ? 1'bz : 1'b0;
	// assign nRomBankSel[15]  =   (!GenBankSel[14] & !GenBankSel[15]) ? 1'bz : 1'b0;

	assign IntRTC	= 1'b0; // 0 for internal and 1 for external
	assign RTC_AS  = FE3x && (bbc_ADDRESS[3:2] == 2'b10) && !RnW && Phi2 && !IntRTC; // &FE38..B -> Address Strobe
	assign RTC_DS  = FE3x && (bbc_ADDRESS[3:2] == 2'b11) && Phi2 && !IntRTC;  // &FE3C..F -> Data Strobe
	// assign nRomBankSel[10]  =	 FE3x && (bbc_ADDRESS[3:2] == 2'b10) && !RnW && Phi2 && IntRTC; // &FE38..B -> Address Strobe
	// assign nRomBankSel[12]  =	 FE3x && (bbc_ADDRESS[3:2] == 2'b11) && Phi2 && IntRTC;  // &FE3C..F -> Data Strobe
	
	// assign nRomBankSel[8]  = 1'b1; // temporary disable on board ROM
	// assign nRomBankSel[9]  = 1'b1; // temporary disable on board ROM
	// assign nRomBankSel[10] = 1'b1; // temporary disable on board ROM
	// assign nRomBankSel[11] = 1'b1; // temporary disable on board ROM
	// assign nRomBankSel[12] = 1'b1; // temporary disable on board ROM
	// assign nRomBankSel[13] = 1'b1; // temporary disable on board ROM
	// assign nRomBankSel[14] = 1'b1; // temporary disable on board ROM
	// assign nRomBankSel[15] = 1'b1; // temporary disable on board ROM
	
	// Logic to select IntegraB RAM Banks 0..15
	// Check if bank is mapped to ROM on either beeb motherboard / IntegraB board, or to RAM on IntegraB board
	assign RamBankSel[0]	  = !(GenBankSel[0]  & !BeebRomSel[0]);
	assign RamBankSel[1]	  = !(GenBankSel[1]  & !BeebRomSel[1]);
	assign RamBankSel[2]	  = !(GenBankSel[2]  & !BeebRomSel[2]);
	assign RamBankSel[3]	  = !(GenBankSel[3]  & !BeebRomSel[3]);
	assign RamBankSel[4]	  = !(GenBankSel[4]);
	assign RamBankSel[5]	  = !(GenBankSel[5]);
	assign RamBankSel[6]	  = !(GenBankSel[6]);
	assign RamBankSel[7]	  = !(GenBankSel[7]);
	assign RamBankSel[8]	  = !(GenBankSel[8]  & !IntegraRomSel[8]);
	assign RamBankSel[9]	  = !(GenBankSel[9]  & !IntegraRomSel[9]);
	assign RamBankSel[10]  = !(GenBankSel[10] & !IntegraRomSel[10]);
	assign RamBankSel[11]  = !(GenBankSel[11] & !IntegraRomSel[11]);
	assign RamBankSel[10]  = !(GenBankSel[10]);
	assign RamBankSel[11]  = !(GenBankSel[11]);
	assign RamBankSel[12]  = !(GenBankSel[12] & !IntegraRomSel[12]);
	assign RamBankSel[13]  = !(GenBankSel[13] & !IntegraRomSel[13]);
	assign RamBankSel[14]  = !(GenBankSel[14] & !IntegraRomSel[14]);
	assign RamBankSel[15]  = !(GenBankSel[15] & !IntegraRomSel[15]);
	assign RAM_CE			  =   RamBankSel[0]  & RamBankSel[1]  & RamBankSel[2]  & RamBankSel[3]
								  &   RamBankSel[4]  & RamBankSel[5]  & RamBankSel[6]  & RamBankSel[7]
								  &   RamBankSel[8]  & RamBankSel[9]  & RamBankSel[10] & RamBankSel[11]
								  &   RamBankSel[12] & RamBankSel[13] & RamBankSel[14] & RamBankSel[15] & !ShadowSel;
	// assign RAM_CE = 1'b1; // temporary disable on board RAM

	// RAM addresses A0..A13 and data lines D0..D7 are wired to the CPU (via buffers on the IntegraB board)
	// RAM addresses A14..A18 are switched by the CPLD based on which RAM bank has been selected
	// ShadowSel is a 32k block based on Shadow RAM and Private RAM. A14 switches between the upper and lower bank.
	assign Ram_ADDRESS[14] = rD0 & !ShadowSel
								  | bbc_ADDRESS[14] & ShadowSel;
	assign Ram_ADDRESS[15] = rD1 & !ShadowSel;
	assign Ram_ADDRESS[16] = rD2 & !ShadowSel;
	assign Ram_ADDRESS[17] = rD3 & !ShadowSel;
	assign Ram_ADDRESS[18] = ShadowSel;

	// Logic to enable the data buffer.
	// Buffer needs to be enabled (logic low) when accessing onboard SWRAM, SWROM, Shadow RAM, Private RAM, or when writing data to registers &FE30..&FE3F

	assign nRomBankSel[8]	= Phi2; //Used to pick up Phi2 for Logic Analyser
	assign nRomBankSel[10]	= RTC_AS; //Used to pick up RTC_AS for Logic Analyser
	assign nRomBankSel[12]	= RTC_DS; //Used to pick up RTC_DS for Logic Analyser

	assign nRomBankSel[11]	= RnW; //Used to drive temporary data buffer direction
	assign nRomBankSel[13]	= !SWRAddr & !ShadowSel & !FE3x // Used to drive the temporary data buffer CE
									| !nRomBankSel0_3 & !ShadowSel & !FE3x; // this line ensures the IntegraB data buffer not active when accessing off board SWROM
	assign nDBuf_CE     	   =  1'b0; // Temporary force chip enable so data can get to CPLD
	// assign nDBuf_CE     	  =  !SWRAddr & !ShadowSel & !FE3x
	// 							  |  !nRomBankSel0_3 & !ShadowSel & !FE3x; // this line ensures the IntegraB data buffer not active when accessing off board SWROM
	// assign nDBuf_CE	     	=  !SWRAddr & !ShadowSel & !FE30_7
	//								|  !nRomBankSel0_3 & !ShadowSel & !FE30_7; // this line ensures the IntegraB data buffer not active when accessing off board SWROM


	//This data is latched when address is in the range FE30..FE33
	//rD0..rD3 are used to decode the selected SWROM bank
   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD0 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD0 <= bbc_DATA[0];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD1 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD1 <= bbc_DATA[1];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD2 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD2 <= bbc_DATA[2];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD3 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD3 <= bbc_DATA[3];
      end
   end

	//PrvEn is used in conjunction with addresses in the range &8000..& to select Private RAM
   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvEn <= 1'b0;
      end else if (!RnW && FE30_3) begin
         PrvEn <= bbc_DATA[6];
      end
   end
 
	always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         MemSel <= 1'b0;
      end else if (!RnW && FE30_3) begin
         MemSel <= bbc_DATA[7];
      end
   end


	//This data is latched when address is in the range FE34..FE37

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvS8 <= 1'b0;
      end else if (!RnW && FE34_7) begin
         PrvS8 <= bbc_DATA[4];
      end
   end
	
	always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvS4 <= 1'b0;
      end else if (!RnW && FE34_7) begin
         PrvS4 <= bbc_DATA[5];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvS1 <= 1'b0;
      end else if (!RnW && FE34_7) begin
         PrvS1 <= bbc_DATA[6];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         ShEn <= 1'b0;
      end else if (!RnW && FE34_7) begin
         ShEn <= bbc_DATA[7];
      end
   end

endmodule

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Sat Nov 28, 2020 9:34 pm

KenLowe wrote:
Sat Nov 28, 2020 9:22 pm
It may just be the logic analyser that's doing funny things. Everything to the right of the trace, where it's shaded is fine. The bit to the left is where I'm getting both AS and DS pulsing at the same time. That just shouldn't be happening.
The logic analyzer is the wrong tool to try to look for glitches.

(And the FX2 dev board is an especially poor logic analyzer, as it doesn't have any buffering or input threshold control)

You would be better switching to the scope and using a glitch (or pulse width) triggering mode.

Start with the trigger threshold to ~1.0V, and look high going AS or DS pulses that are < 100ns.

There should be none.
KenLowe wrote:
Sat Nov 28, 2020 9:22 pm
I'm also not sure why I'm getting sections of blank data. I'm guessing data's not getting transferred over to the PC quickly enough.
Those will be when the MOS is servicing and interrupt (the large onces occur every 10ms).

If you want to avoid them, put an SEI at the start of your code.

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Nov 28, 2020 10:11 pm

hoglet wrote:
Sat Nov 28, 2020 9:34 pm
You would be better switching to the scope and using a glitch (or pulse width) triggering mode.

Start with the trigger threshold to ~1.0V, and look high going AS or DS pulses that are < 100ns.

There should be none.
Right, that's me learned something new about my scope. I can confirm that I'm not getting any AS or DS pulses <100ns. Just to make sure I'd set it up correctly, I changed to setting to <300ns and it picks up both AS and DS pulses. I did try this the other day, but I used the wrong setting. I was trying to use duration instead of pulse, but I couldn't get that to work.

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Sat Nov 28, 2020 10:27 pm

With the trigger pulse width set to 100ns, slowly reduce the trigger level from 1V down towards 0V. At some point it will start triggering on noise. Note the trigger level where that occurs. Do this for each of RTC_AS and RTC_DS.

If it's less than 0.5V then you are fine.

If it's more like 0.8V then this is marginal, as the max voltage for a logic '0' input is typically 0.8V.

Dave

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Nov 28, 2020 10:37 pm

hoglet wrote:
Sat Nov 28, 2020 10:27 pm
With the trigger pulse width set to 100ns, slowly reduce the trigger level from 1V down towards 0V. At some point it will start triggering on noise. Note the trigger level where that occurs. Do this for each of RTC_AS and RTC_DS.

If it's less than 0.5V then you are fine.

If it's more like 0.8V then this is marginal, as the max voltage for a logic '0' input is typically 0.8V.

Dave
Great test. Both are triggering at about 450mV.

Edit: Actually, the trigger levels for the onboard RTC are about half of that at about 200mV. The 450mV signals I was measuring was taken from a pair of temporary RTC_AS and DS outputs from the CPLD that I'm using to drive the logic analyser.

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Nov 28, 2020 11:07 pm

Here's the scope results.

Yellow: Phi2
Cyan: RTC_AS
Magenta: RTC_DS
Blue: RnW

The first trace shows (left to right):

Write &55 to address &20 (first AS and DS pulse)
Read data from address &20 (second AS and DS pulse)
Write &AA to address &20 (third AS and DS pulse)
Read data from address &20 (forth AS and DS pulse)

The second scope trace is a zoom in of the Address Strobe and the third scope trace shows a zoom in of the Data Strobe. Both of these show the rising edge of RnW occurring approximately 55ns after the falling edge of AS / DS, which is good, I guess! But it doesn't explain why I can't get the damned thing to work!

Unless anyone can suggest anything else to look at, I might try hooking up the user and printer ports to the RTC so I can more selectively control the three key signals that control the RTC.
DS1Z_QuickPrint49.png
Two cycles of Read / Write
RTC-Capture13.PNG
...and equivalent Logic Analyser trace
DS1Z_QuickPrint50.png
Zoom in of Address Strobe
DS1Z_QuickPrint51.png
Zoom in of Data Strobe

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sun Nov 29, 2020 12:31 am

KenLowe wrote:
Sat Nov 28, 2020 3:31 pm
I tend to believe the value &D1 is genuinely what is held at address &20. The value I read stays the same, regardless of what I try to write. If I switch to address &21, I consistently read the value &71, and if I switch back to address &20 again I get the value &D1 again
hoglet wrote:
Sat Nov 28, 2020 3:34 pm
That suggests it's the RTC write that is failing.
A little bit more information to support the fact that reading from the RTC is working. I have now applied a nRCLR to pin 21 of the RTC, and now when I read from registers &21 and &22, I get the value &FF, which is what the datasheet says should happen after a remote clear.

Edit: Actually scrub that. Now every address is responding with &FF, which I don't think is right. Only the 'general-purpose' RAM should have been cleared. The registers that hold the clock data (0..9) should not have cleared, but they are also responding with &FF. This tells me that possibly the wrong address is being latched.

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Sun Nov 29, 2020 9:49 am

KenLowe wrote:
Sat Nov 28, 2020 11:07 pm
The second scope trace is a zoom in of the Address Strobe and the third scope trace shows a zoom in of the Data Strobe. Both of these show the rising edge of RnW occurring approximately 55ns after the falling edge of AS / DS, which is good, I guess! But it doesn't explain why I can't get the damned thing to work!
Yes, that's fine, and is the sort of margin I would expect.

This really is somewhat of a mystery.

I have slightly lost track of what previous experiments you have done:
- did you get the DS12885 working with your through-hole board with the original PALs?
- did you get the DS12885 working with your through-hole board with the dangling CPLD?
- have you tried an alternative DS12885 part in the SMT board? Was it from the same source?
- were the DS12885 parts bought from a UK distributor? RS and Farnell both stock them.

Dave

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sun Nov 29, 2020 11:41 am

hoglet wrote:
Sun Nov 29, 2020 9:49 am
I have slightly lost track of what previous experiments you have done:
- did you get the DS12885 working with your through-hole board with the original PALs?
I've not tried this in a while. I couldn't get to work the last time I tried it, but that was before I discovered the issue with battery. However, when I tried it previously, I do think I also tried it with VBat input tied to Gnd at one point, which should have worked, but didn't. I will try that setup again shortly.
hoglet wrote:
Sun Nov 29, 2020 9:49 am
- did you get the DS12885 working with your through-hole board with the dangling CPLD?
Yes, that one's working fine. I can get both DIP and SOIC (soldered to a carrier board) versions to work. Addressing the battery issue got that one working.
hoglet wrote:
Sun Nov 29, 2020 9:49 am
- have you tried an alternative DS12885 part in the SMT board? Was it from the same source?
All SMT RTC devices came from the same source. I've tried a few things here.
  • Firstly, I replaced the RTC on my first V2 board. That didn't make any difference. That is a fully populated board that I cut the data tracks on. This is the board that I was testing with yesterday.
  • A few days ago I also soldered up a RTC to a second V2 board. I haven't added the SMT RAM IC to this board. Instead I've used a few 32K DIP RAM ICs plugged into the IntegraB 28 pin ROM / RAM sockets. I couldn't get the RTC on this board to work either.
  • The other day I also tried hooking up a DIP and SOIC (via carrier board) RTC remotely to my first V2 board. Initially I connected the data lines direct to the CPU (upstream of the IntegraB data buffer), and that worked just fine. I then tied in the data lines downstream of the data buffer, and that also worked just fine. To access the SMT RAM, I had to install jumper wires to fix the cuts I had previously made on the data lines.
  • Yesterday, I added an additional external data buffer to my first V2 board. This was hooked into the V2 board in such a way that it communicated with the onboard RAM and RTC. The original onboard data buffer was still tied to the CPLD, so I set the CE to be always active, and forced the Data direction to always be towards the CPLD (it just uses the data for ROM address decoding and Shadow / Private RAM switching). This is the arrangement I was testing with yesterday. The onboard RTC would not respond correctly.
hoglet wrote:
Sun Nov 29, 2020 9:49 am
- were the DS12885 parts bought from a UK distributor? RS and Farnell both stock them.
I think they came from China. The one which I soldered onto the carrier board is the only one I can get working.

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Mon Nov 30, 2020 12:58 pm

BigEd wrote:
Mon Nov 09, 2020 9:56 am
Might be worth noting that poking in Basic with the ? operator is an indexed operation (I think...) and so the sequence of accesses might not be quite what you expect. Might be worth trying a store absolute in assembly to see if there's any difference.
I have been testing on my computer with the V2 IntegraB board, where I have disabled the onboard SOIC RTC, and provided a facility to hook up an external DIP RTC. I've then been testing with various different RTCs, and I am definitely seeing some impact of this indexed operation with some RTCs. The tests are fairly simple. Firstly in assembly:

Code: Select all

.write55
LDA #&20
STA &FE38; select register &20
LDA #&55
STA &FE3C; write &55 to register &20
RTS

.writeAA
LDA #&20
STA &FE38; select register &20
LDA #&AA
STA &FE3C; write &AA to register &20
RTS

CALL write55
?&FE38=&20
P.?&FE3C; read contents of register &20
CALL writeAA
?&FE38=&20; read contents of register &20
P.?&FE3C
With the a CDP6818(E) hooked up, the Basic code responds as expected with the values &55 and &AA.
With the slightly newer CPD6818A(E) (which has slightly different pinout that I've allowed for) it also responds correctly with &55 and &AA.

Next if I use the above code to clear register &20 (setting it to &00) and run the following Basic code, I get different results:

Code: Select all

?&FE38=&20
?&FE3C=&55; write &55 to register &20
?&FE38=&20
P.~?&FE3C; read contents of register &20

?&FE38=&20
?&FE3C=&AA; write &AA to register &20
?&FE38=&20
P.~?&FE3C; read contents of register &20
With the a CDP6818(E) hooked up, it responds as expected with the values &55 and &AA.
With the CPD6818A(E) it responds differently. Instead it responds with the value previously stored at register &20. In this case &00 and &00. For some reason, the new values are not being updated to register &20. Curiously, though, the Basic code is able to set the correct register to be read from. If I use the assembly language routine to set the value in register &21 to something different, I can then use the basic routine to switch between registers 20 & 21 and it will correctly read the results. The part that appears to be failing under Basic is where I do a Data Strobe write (?&FE3C=xx). The Address Strobe write (?&FE38=xx) seems to work fine. Go figure :?!

Edit: Corrected the CDP6818 part numbers!
Last edited by KenLowe on Mon Nov 30, 2020 6:15 pm, edited 1 time in total.

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Mon Nov 30, 2020 5:40 pm

KenLowe wrote:
Mon Nov 30, 2020 12:58 pm
The part that appears to be failing under Basic is where I do a Data Strobe write (?&FE3C=xx). The Address Strobe write (?&FE38=xx) seems to work fine. Go figure :?!
Here's what's going on with ?&FE38C=xx, and possibly an explanation of the difference between AS cycles and DS cycles.

I did a ICE trace of ?&FE3C=&55 with a watch point, and in Basic 2 the following instruction does the write:

Code: Select all

>> d b4ca
B4CA : 91 37    : STA ($37),Y
B4CC : A5 39    : LDA $39
B4CE : F0 0F    : BEQ $B4DF
B4D0 : A5 2B    : LDA $2B
B4D2 : C8       : INY 
B4D3 : 91 37    : STA ($37),Y
B4D5 : A5 2C    : LDA $2C
B4D7 : C8       : INY 
B4D8 : 91 37    : STA ($37),Y
B4DA : A5 2D    : LDA $2D
>> r
6502 Registers:
  A=55 X=37 Y=00 SP=01FD PC=B4CC
  Status: --------
>>
The STA (ZP), Y takes 6 bus cycles:

Code: Select all

        #    address   R/W description
       --- ----------- --- ------------------------------------------
        1      PC       R  fetch opcode, increment PC
        2      PC       R  fetch pointer address, increment PC
        3    pointer    R  fetch effective address low
        4   pointer+1   R  fetch effective address high,trafs
                           add Y to low byte of effective address
        5   address+Y*  R  read from effective address,
                           fix high byte of effective address
        6   address+Y   W  write to effective address

       Notes: The effective address is always fetched from zero page,
              i.e. the zero page boundary crossing is not handled.

              * The high byte of the effective address may be invalid
                at this time, i.e. it may be smaller by $100.
So in your case, cycle 5 will be a Read from &FE38/C, and cycle 6 will be a Write to &FE38/C.

In the case of writing to &FE38, the suprious read should be harmless, because AS will not be generated by your CPLD.

In the case of writing to &FE3C, you end up generating two DS cycles, back-to-back, the first being a read cycle and the second a write cycle.

The CDP6818 seems quite slow (min cycle time is 953ns, min pulse width DS high is 325ns). You are violating both of those specs with the back-to-back DS cycles.

Do you have a data sheet for the CDP6818E?

Dave

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Mon Nov 30, 2020 6:13 pm

Thanks for that explanation. That's very interesting.
hoglet wrote:
Mon Nov 30, 2020 5:40 pm
Do you have a data sheet for the CDP6818E?
I've just realised I was quoting the wrong part in my previous post. The two tests were with the CDP6818E and the CDP6818AE. I think the E is just the packaging type (Plastic). The CDP6818A(E) is the newer one that didn't work correctly in Basic. TBH, that's not really a problem. The IBOS is using assembly language to communicate with the RTC. Here's an extract from the ROM that deals with RTC reads and writes. I'm not sure why it does an &0D Address Strobe after every read / write operation, or the what the purpose of the NOP delays is:

Code: Select all

;read from RTC RAM (Addr = X, Data = A)
.rdRTCRAM	  PHP
            SEI
            JSR LA66C								;Set RTC address according to X
            LDA SHEILA+&3C								;Strobe out data
            JSR LA664
            PLP
            RTS
			
;write to RTC RAM (Addr = X, Data = A)
.wrRTCRAM	  PHP
            JSR LA66C								;Set RTC address according to X
            STA SHEILA+&3C								;Strobe in data
            JSR LA664
            PLP
            RTS
			
.LA660      NOP
.LA661      NOP
            NOP
            RTS
			
.LA664      PHA
            LDA #&0D								;Select 'Register D' register on RTC: Register &0D
            JSR LA66C
            PLA
            RTS
			
.LA66C      SEI
            JSR LA661								;2 x NOP delay
            STX SHEILA+&38								;Strobe in address
            JMP LA660								;3 x NOP delay
I'll update this post shortly to include a copy of the two datasheets (CDP6818 and CDP6818A).

Edit: Now attached:
CDP6818-Harris Semiconductor.pdf
CDP6818(E)
(823.84 KiB) Downloaded 11 times
CDP6818AE.pdf
CDP6818A(E)
(1.07 MiB) Downloaded 13 times

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Mon Nov 30, 2020 6:34 pm

hoglet wrote:
Mon Nov 30, 2020 5:40 pm
The STA (ZP), Y takes 6 bus cycles:

Code: Select all

        #    address   R/W description
       --- ----------- --- ------------------------------------------
        1      PC       R  fetch opcode, increment PC
        2      PC       R  fetch pointer address, increment PC
        3    pointer    R  fetch effective address low
        4   pointer+1   R  fetch effective address high,trafs
                           add Y to low byte of effective address
        5   address+Y*  R  read from effective address,
                           fix high byte of effective address
        6   address+Y   W  write to effective address

       Notes: The effective address is always fetched from zero page,
              i.e. the zero page boundary crossing is not handled.

              * The high byte of the effective address may be invalid
                at this time, i.e. it may be smaller by $100.
So in your case, cycle 5 will be a Read from &FE38/C, and cycle 6 will be a Write to &FE38/C.

In the case of writing to &FE38, the suprious read should be harmless, because AS will not be generated by your CPLD.

In the case of writing to &FE3C, you end up generating two DS cycles, back-to-back, the first being a read cycle and the second a write cycle.

The CDP6818 seems quite slow (min cycle time is 953ns, min pulse width DS high is 325ns). You are violating both of those specs with the back-to-back DS cycles.

Do you have a data sheet for the CDP6818E?

Dave
I'm guessing it's just the zero page instruction that gives us these two DS cycles, given that I only saw a single pulse on the previous scope traces during a STA absolute instruction. In which case, that's not really a problem because in practice I don't actually need to use the Basic ?&FE3C instruction. It can all be done in assembly with STA absolute.

Edit 1: A quick look at the datasheets, and I note that the cycle time for CDP6818 & CDP6818A are both the same at 953ns, whereas the DS12885 is 385ns. Similarly, the min pulse width DS high for CDP6818 & CDP6818A are both the same at 325ns whereas the DS12885 is 125ns.

It's interesting that I don't have any problems with the slower CDP6818s, it's the faster DS12885 that's giving me the problem!

Edit 2: Let me qualify that last statement. The two different CDP6818s, the faster DS12885 and the BQ3285 all work fine if I take the RTC offboard. I just can't get the onboard DS12885 to work!

Would I be correct in stating that the pulse width of both DS and AS is 250ns (half the period of the Phi2 clock)? So, within the DS12885 spec, but not the CDP6818 spec?

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Tue Dec 01, 2020 4:16 pm

Hmmm. Datasheet states:
DS12885 datasheet wrote:ABSOLUTE MAXIMUM RATINGS
Lead Temperature (soldering, 10s) .................................+260°C
My iron has been running a lot hotter than that (it's currently set at 400DegC), but is typically on a single pin for less than a second. What's the likelihood that's caused damage? I'm using lead free solder which is why I'm running it hotter, but I'm guessing 250DegC might be a more appropriate temperature and still be within the RTC spec? I'll probably lift off the one I've previously soldered on at the higher temperature, and replace it with one soldered in at a lower temperature. Thoughts?

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Tue Dec 01, 2020 11:56 pm

I've removed the RTC from one of my V2 IntegraB boards, and soldered it onto a carrier boards so I could test on my development machine, and it's not working. I have another identical carrier board with a RTC soldered onto it, and it works just fine, so my guess is that the one I removed from the V2 board is faulty; either I damaged it when I soldered it on, or it's always been faulty. I plan to do some further tests on this faulty RTC later this week, using the user and printer port to control the various signals.

I also soldered another RTC onto my V2 board but it's not working either, so I'm either damaging these things when I solder them to the board, or they're just plain faulty. I'm struggling to get the solder to melt on anything less than about 330DegC!

I've just discovered that I have a 28 pin SOIC - DIP adaptor board that came with my EPROM programmer that I can fit the RTC into, so I'm going to try testing them in that adaptor prior to soldering any more onto the boards. Only issue is that I'll need to use even more dupont wires to connect it to my dev machine, and I suspect that may cause other issues...

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Wed Dec 02, 2020 8:00 pm

KenLowe wrote:
Tue Dec 01, 2020 11:56 pm
I've just discovered that I have a 28 pin SOIC - DIP adaptor board that came with my EPROM programmer that I can fit the RTC into, so I'm going to try testing them in that adaptor prior to soldering any more onto the boards. Only issue is that I'll need to use even more dupont wires to connect it to my dev machine, and I suspect that may cause other issues...
Tried this last night with a variety of 'new' DS12885 ICs, but I couldn't get any of them to work in my development beeb. The adaptor board uses spring clips to make contact with the legs of the RTC, and I'm not sure how good a connection I'm getting. I'm also using dupont wires to connect between the adaptor board and the IntegraB board on this development beeb, and that might also be having an impact.

I've taken one of these 'new' RTC ICs and soldered it onto yet another carrier board, so I now have three carrier boards with SMT DS12885 soldered onto it. I believe all 3 of these RTCs have come from the same source (in China):

RTC carrier board 1
The RTC was brand new when I soldered it onto the carrier board. I was initially trying to get this working on my V1 IntegraB board but it would never work reliably. More recently I traced the issue down to an out of tolerance VBat input. With that input now within spec, this RTC works perfectly on the dev machine.

RTC carrier board 2
The RTC that I'm using on this carrier board was removed from one of my V2 IntegraB boards. It didn't work on the V2 board, and it still doesn't work on this carrier board.

RTC carrier board 3
The RTC that I'm using on this carrier board is one of the new ones that I unsuccessfully tried to get working with the 28 pin SOIC - DIP adaptor board. It does sometimes respond in the dev machine, but not reliably.

In summary, I've got one SMT based RTC working reliably out of three. I'm discounting the tests with the 28 pin SOIC - DIP adaptor board, because I'm not convinced I'm getting reliable connections to the chip.

I have also tested a number of DIP based DS12885 and BQ3285 RTCs on the same dev machine, and they all work fine (now that VBat is in spec!).

So, bottom line here is that I suspect this batch of RTCs may be faulty. I've ordered up a couple from RS Online, and I'm just waiting for those to be delivered. I'm hoping to pick them up from the trade desk tomorrow. I've also ordered a few BQ3285 ICs from China to see if they work any better.

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Fri Dec 04, 2020 3:37 pm

KenLowe wrote:
Wed Dec 02, 2020 8:00 pm
So, bottom line here is that I suspect this batch of RTCs may be faulty. I've ordered up a couple from RS Online, and I'm just waiting for those to be delivered. I'm hoping to pick them up from the trade desk tomorrow. I've also ordered a few BQ3285 ICs from China to see if they work any better.
I picked up the DS12885 RTCs from RS this afternoon and have given one of them a test. Initially, I tried it with the spring contact adaptor board, but it didn't work. I then soldered it onto another one of my carrier boards and tested that instead. Confidence wasn't that high given that it didn't work with the spring contact adaptor board, but much to my surprise, it works! That tells me that the spring contact adaptor board is not reliable, so I'll ditch that from any further testing.

I'm not breaking out the Champaign quite yet. I'm not sure that a sample of one IC from RS is enough to confirm that the batch I bought from China is faulty. Next up, I'm going to solder the other RS bought RTC onto one of my other IntegraB V2 boards and see how well it works on that board. Baby steps...

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Fri Dec 04, 2020 4:03 pm

Fingers crossed [-o< [-o< [-o< [-o<

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Fri Dec 04, 2020 6:05 pm

hoglet wrote:
Fri Dec 04, 2020 4:03 pm
Fingers crossed [-o< [-o< [-o< [-o<
It works!!!!

That's the first time I've been able to get the RTC working in a V2 board. I'm still using a batch of temporary 32K RAM ICs instead of the onboard RAM, but I'll get that soldered in next, and hopefully I'll have a fully functional board. Well, apart from the fact that I've got Phi2 temporarily patched in, the Supervisor IC is currently bypassed, and the battery circuit needs to be changed. But functionally it currently does what I want. Shadow RAM working, Sideways RAM working, RTC working. All controlled via the CPLD :D.

Thank you all for helping me get this far. Couldn't have done it without you guys!

Edit: Soldered in the RAM and re-enabled the Supervisor IC (using nRDS instead of A13 for the watchdog), and everything is almost working. The RTC is still working, all 16 sideways RAM banks seem to be working, the Shadow and Private RAM seems to be working. However, when I try and play Lancelot or Time & Magik, I get odd corruption in the game. I suspect the Supervisor IC is getting in the way of the RAM CE again. I'll try bypassing that and see if it starts working again.

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Dec 05, 2020 8:42 pm

KenLowe wrote:
Fri Dec 04, 2020 6:05 pm
Edit: Soldered in the RAM and re-enabled the Supervisor IC (using nRDS instead of A13 for the watchdog), and everything is almost working. The RTC is still working, all 16 sideways RAM banks seem to be working, the Shadow and Private RAM seems to be working. However, when I try and play Lancelot or Time & Magik, I get odd corruption in the game. I suspect the Supervisor IC is getting in the way of the RAM CE again. I'll try bypassing that and see if it starts working again.
It's been another frustrating day, but I think I'm there now...

I bypassed the Supervisor IC altogether, by wiring the RAM CE signal directly from the CPLD, but the RAM still misbehaved. Lancelot and Time & Magik (both of which use shadow and sideways RAM) wouldn't run reliably; it was particularly noticeable if DFS was also running from a RAM bank. The annoying thing was that if I tried to load a ROM into any RAM bank, it would load and verify ok but it appeared that, when a program needed to switch between these RAM banks, things would start going wrong. Write protect (where appropriate) didn't make any difference. If I modified the CPLD to select 4 x external 32K RAM ICs (one for shadow and the other three for 6 banks of sideways RAM) instead of the internal RAM IC everything would work properly.

After much head scratching, and even though everything seemed to bell out ok, I decided to run the soldering iron over the RAM pins again and that seems to have cured it. Lancelot and Time & Magik are both now loading and running as I would expect. The RTC is also working :). That's me now got 16 individually write protectable RAM banks (12 of which can be individually switched to external ROM sockets, 8 on the IntegraB board and 4 on the beeb motherboard), Shadow RAM & RTC all working.

I'm now going to connect the Supervisor IC back in again to see if I can get that to work reliably.

For anyone who's interested, here's the latest code. This code still uses a temporary input for the Phi2 clock. This will be corrected in the final board layout.
Edit: Code updated to temporarily use Phi1 clock instead of Phi2 (see post below). It surprisingly works in this configuration, and allows me to remove that Phi2 patch wire. I will revert back to using Phi2 on a global clock input in the next board revision.

Code: Select all

`timescale 1ns / 1ps
/************************************************************************
	 IntegraBV2.v

	 IntegraB V2 - A fully expanded ROM / RAM Board for BBC Micro
	 Revision 01 - December 2020
    Copyright (C) 2020 Ken Lowe

    IntegraBV2 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 program 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/>.

	 Email: ken@skidog.co.uk

************************************************************************/
module IntegraBV2(
	input from_CPU_RnW,
	input from_CPU_Phi1,
	//	input from_CPU_Phi2, //Temporary input (borrowed output nROMBankSel[14] - Pin 27, GCLK 3)
	input from_CPU_dPhi2,
	input bbc_nRST,
	input [7:0] bbc_DATA,
	input [15:0] bbc_ADDRESS,
	input [15:0] RamWriteProt,
	input [15:8] IntegraRomSel,
	input [3:0] BeebRomSel,

	output to_bbc_Phi1,
	output to_bbc_RnW,
	output to_bbc_rD0,
	output to_bbc_rD1,
	output nDBuf_CE,
	output nDBuf_Dir,
	output nWDS,
	output nRDS,
	output nRomBankSel0_3,
	output [15:8] nRomBankSel,
	output RTC_AS,
	output RTC_DS,
	output nRAM_CE,
	output [18:14] Ram_ADDRESS
	);


	// Repeat RnW & Phi1 from Input to Output
	wire	 Phi1;
	wire	 Phi2;
	wire	 ShAct;
	wire	 RnW;
	assign Phi1			 = from_CPU_Phi1;
	assign Phi2			 = !from_CPU_Phi1;
	//	assign Phi2			 = from_CPU_Phi2;
	assign RnW			 = from_CPU_RnW;
	assign to_bbc_Phi1 = !(!Phi1 & !ShAct);
	assign to_bbc_RnW  = !(!RnW  & !ShAct);
	assign nDBuf_Dir	 = RnW;

	// Address decoding. Note that the lowest 2 bits A0 and A1 are not used.
	wire   FE3x		= (bbc_ADDRESS[15:4] == 12'hFE3);
	wire   FE30_3  = FE3x && (bbc_ADDRESS[3:2] == 2'b00);
	wire   FE34_7  = FE3x && (bbc_ADDRESS[3:2] == 2'b01);
	wire   FE38_B  = FE3x && (bbc_ADDRESS[3:2] == 2'b10);
	wire   FE3C_F  = FE3x && (bbc_ADDRESS[3:2] == 2'b11);
	
	// nWDS is normally just !( RnW & !Phi1) but we check for Write protect and hold nWDS high is Write Protect is active.
	// nWDS needs to consider all 16 RAM banks AND the Shadow Bank
	wire	 ShadowSel;
	wire   nRamBankSel[15:0];
	wire	 GenBankSel[15:0];
	assign nRDS = !( RnW & Phi2);
	assign nWDS = !((!RnW & Phi2 & !nRamBankSel[0]  & !RamWriteProt[0]  & !BeebRomSel[0])
					|   (!RnW & Phi2 & !nRamBankSel[1]  & !RamWriteProt[1]  & !BeebRomSel[1])
					|   (!RnW & Phi2 & !nRamBankSel[2]  & !RamWriteProt[2]  & !BeebRomSel[2])
					|   (!RnW & Phi2 & !nRamBankSel[3]  & !RamWriteProt[3]  & !BeebRomSel[3])
					|	 (!RnW & Phi2 & !nRamBankSel[4]  & !RamWriteProt[4])
					|   (!RnW & Phi2 & !nRamBankSel[5]  & !RamWriteProt[5])
					|   (!RnW & Phi2 & !nRamBankSel[6]  & !RamWriteProt[6])
					|   (!RnW & Phi2 & !nRamBankSel[7]  & !RamWriteProt[7])
					|   (!RnW & Phi2 & !nRamBankSel[8]  & !RamWriteProt[8]  & !IntegraRomSel[8])
					|   (!RnW & Phi2 & !nRamBankSel[9]  & !RamWriteProt[9]  & !IntegraRomSel[9])
					|   (!RnW & Phi2 & !nRamBankSel[10] & !RamWriteProt[10] & !IntegraRomSel[10])
					|   (!RnW & Phi2 & !nRamBankSel[11] & !RamWriteProt[11] & !IntegraRomSel[11])
					|   (!RnW & Phi2 & !nRamBankSel[12] & !RamWriteProt[12] & !IntegraRomSel[12])
					|   (!RnW & Phi2 & !nRamBankSel[13] & !RamWriteProt[13] & !IntegraRomSel[13])
					|   (!RnW & Phi2 & !nRamBankSel[14] & !RamWriteProt[14] & !IntegraRomSel[14])
					|   (!RnW & Phi2 & !nRamBankSel[15] & !RamWriteProt[15] & !IntegraRomSel[15])
					|   (!RnW & Phi2 &  ShadowSel));

	// This logic sets PrvAct to logic state '1' if the addresses in the Private memory range &8000..&AFFF and if one of the Private Memory flags is active. 
	reg	 PrvEn;
	reg	 PrvS8;
	reg	 PrvS4;
	reg	 PrvS1;
	assign PrvAct    =   ((bbc_ADDRESS[15:12] == 4'h8) & (bbc_ADDRESS[11:10] == 2'b00) & PrvS1 & PrvEn  //address decodes to &8000..&83FF. Maps to &0000..&03FF in Shadow RAM
						  |    (bbc_ADDRESS[15:12] == 4'h8) &  PrvS4 & PrvEn   										 //address decodes to &8000..&8FFF. Maps to &0000..&0FFF in Shadow RAM
						  |    (bbc_ADDRESS[15:12] == 4'h9) &  PrvS8 & PrvEn											 //address decodes to &9000..&9FFF. Maps to &1000..&1FFF in Shadow RAM
						  |    (bbc_ADDRESS[15:12] == 4'hA) &  PrvS8 & PrvEn);										 //address decodes to &A000..&AFFF. Maps to &2000..&2FFF in Shadow RAM

	// This logic sets ShAct to logic state '1' if the addresses in the screen range &3000..&7FFF and if Shadow Memory is active. 
	reg	 ShEn;
	reg	 MemSel;
	wire	 ScreenMem =  ((bbc_ADDRESS[15:12] == 4'h3)    //address decodes to &3000..&3FFF
						  |   (bbc_ADDRESS[15:14] == 2'b01)); //address decodes to &4000..&7FFF
	assign ShAct     = ScreenMem & ShEn & !MemSel;

	// ShadowSel is logic '1' when either Shadow or Private RAM is being accessed. 
	// Note that Shadow and Private memory is mapped to a 32k Block of RAM as follows:
	// Function      | BBC Memory	| 32K RAM
	// --------------+------------+-----------
	//	Screen memory | 3000..7FFF	| 3000..7FFF
	//	Private Prv1  | 8000..83FF	| 0000..03FF
	// Private Prv4  | 8000..8FFF	| 0000..0FFF
	// Private Prv8  | 9000..AFFF | 1000..2FFF
	assign ShadowSel = !(!ShAct & !PrvAct);

	// The following logic is used to demux the ROM banks.
	// Banks 0..3 are located on the Beeb mainboard. These banks can be switched out for SWRAM on the IntegraB board instead
	// Banks 4..7 are SWRAM banks located on the IntegraB board
	// Banks 8..15 are ROM slots on the IntegraB board. These banks can be switched out for SWRAM on the IntegraB board instead
	// All SWRAM can be write protected in 16k banks.
	reg	 rD0;
	reg	 rD1;
	reg	 rD2;
	reg	 rD3;
	wire	 ROMDec;
	assign to_bbc_rD0 = rD0;
	assign to_bbc_rD1 = rD1;

	// If address is in range &8000..&BFFF then SWRAddr = 1, otherwise 0
	wire	 SWRAddr  =  (bbc_ADDRESS[15:14] == 2'b10);

	// Check if address is in the range &8000..&BFFF and it's not Private RAM that's being accessed.
	assign ROMDec   =  (SWRAddr & !PrvAct & Phi2
						 |	  SWRAddr & !PrvAct & !nRomBankSel0_3);

	// GenBankSel[x] is logic '1' when bank is selected
	// wire	 GenBankSel[15:0];
	assign GenBankSel[0]   = !rD3 & !rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[1]   = !rD3 & !rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[2]   = !rD3 & !rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[3]   = !rD3 & !rD2 &  rD1 &  rD0 & ROMDec;
	assign GenBankSel[4]   = !rD3 &  rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[5]   = !rD3 &  rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[6]   = !rD3 &  rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[7]   = !rD3 &  rD2 &  rD1 &  rD0 & ROMDec;
	assign GenBankSel[8]   =  rD3 & !rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[9]   =  rD3 & !rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[10]  =  rD3 & !rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[11]  =  rD3 & !rD2 &  rD1 &  rD0 & ROMDec;
	assign GenBankSel[12]  =  rD3 &  rD2 & !rD1 & !rD0 & ROMDec;
	assign GenBankSel[13]  =  rD3 &  rD2 & !rD1 &  rD0 & ROMDec;
	assign GenBankSel[14]  =  rD3 &  rD2 &  rD1 & !rD0 & ROMDec;
	assign GenBankSel[15]  =  rD3 &  rD2 &  rD1 &  rD0 & ROMDec;
	

	// Logic to select Motherboard ROM Banks 0..3
	// Check if bank is mapped to ROM on beeb motherboard, or to RAM on IntegraB board
	// GenBankSel[x] is the output of the 4..16 line decoder. Logic '1' if output is decoded
	//	BeebRomSel[x] is based on jumper selection via pull up resistor. Logic '1' selects motherboard ROM. Logic '0' selects onboard RAM
	// nRomBankSelB[x] is logic '0' when bank is selected otherwire logic '1'
	wire   nRomBankSelB[3:0];
	assign nRomBankSelB[0] = !(GenBankSel[0] & BeebRomSel[0]);
	assign nRomBankSelB[1] = !(GenBankSel[1] & BeebRomSel[1]);
	assign nRomBankSelB[2] = !(GenBankSel[2] & BeebRomSel[2]);
	assign nRomBankSelB[3] = !(GenBankSel[3] & BeebRomSel[3]);
	assign nRomBankSel0_3  = nRomBankSelB[0] & nRomBankSelB[1] & nRomBankSelB[2] & nRomBankSelB[3];

	// Logic to select IntegraB ROM Banks 8..15
	// Check if bank is mapped to ROM on IntegraB board, or to RAM on IntegraB board
	// GenBankSel[x] is the output of the 4..16 line decoder. Logic '1' if output is decoded
	//	IntegraRomSel[x] is based on jumper selection via pull up resistor. Logic '1' selects IntegraB ROM socket. Logic '0' selects onboard RAM
	// nRomBankSel[x] is logic '0' when bank is selected otherwire open collector
	assign nRomBankSel[8]  =  (GenBankSel[8]  & IntegraRomSel[8])  ? 1'b0 : 1'bz;
	assign nRomBankSel[9]  =  (GenBankSel[9]  & IntegraRomSel[9])  ? 1'b0 : 1'bz;
	assign nRomBankSel[10] =  (GenBankSel[10] & IntegraRomSel[10]) ? 1'b0 : 1'bz;
	assign nRomBankSel[11] =  (GenBankSel[11] & IntegraRomSel[11]) ? 1'b0 : 1'bz;
	assign nRomBankSel[12] =  (GenBankSel[12] & IntegraRomSel[12]) ? 1'b0 : 1'bz;
	assign nRomBankSel[13] =  (GenBankSel[13] & IntegraRomSel[13]) ? 1'b0 : 1'bz;
	assign nRomBankSel[14] =  (GenBankSel[14] & IntegraRomSel[14]) ? 1'b0 : 1'bz;
	assign nRomBankSel[15] =  (GenBankSel[15] & IntegraRomSel[15]) ? 1'b0 : 1'bz;

	// Logic to select IntegraB RAM Banks 0..15
	// Check if bank is mapped to ROM on either beeb motherboard / IntegraB board, or to RAM on IntegraB board
	// GenBankSel[x] is the output of the 4..16 line decoder. Logic '1' if output is decoded
	//	IntegraRomSel[x] is based on jumper selection via pull up resistor. Logic '1' selects motherboard ROM. Logic '0' selects onboard RAM
	// nRamBankSel[x] is logic '0' when bank is selected otherwire logic '1'
	assign nRamBankSel[0]	= !(GenBankSel[0]  & !BeebRomSel[0]);
	assign nRamBankSel[1]	= !(GenBankSel[1]  & !BeebRomSel[1]);
	assign nRamBankSel[2]	= !(GenBankSel[2]  & !BeebRomSel[2]);
	assign nRamBankSel[3]	= !(GenBankSel[3]  & !BeebRomSel[3]);
	assign nRamBankSel[4]	= !(GenBankSel[4]);
	assign nRamBankSel[5]	= !(GenBankSel[5]);
	assign nRamBankSel[6]	= !(GenBankSel[6]);
	assign nRamBankSel[7]	= !(GenBankSel[7]);
	assign nRamBankSel[8]	= !(GenBankSel[8]  & !IntegraRomSel[8]);
	assign nRamBankSel[9]	= !(GenBankSel[9]  & !IntegraRomSel[9]);
	assign nRamBankSel[10]  = !(GenBankSel[10] & !IntegraRomSel[10]);
	assign nRamBankSel[11]  = !(GenBankSel[11] & !IntegraRomSel[11]);
	assign nRamBankSel[12]  = !(GenBankSel[12] & !IntegraRomSel[12]);
	assign nRamBankSel[13]  = !(GenBankSel[13] & !IntegraRomSel[13]);
	assign nRamBankSel[14]  = !(GenBankSel[14] & !IntegraRomSel[14]);
	assign nRamBankSel[15]  = !(GenBankSel[15] & !IntegraRomSel[15]);

	// Logic to Enable RAM IC
	// If any RAM bank or shadow / private RAM is being accessed, then nRAM_CE is logic '0' otherwise logic '1'
	assign nRAM_CE				=   nRamBankSel[0]  & nRamBankSel[1]  & nRamBankSel[2]  & nRamBankSel[3]
									&   nRamBankSel[4]  & nRamBankSel[5]  & nRamBankSel[6]  & nRamBankSel[7]
	 								&   nRamBankSel[8]  & nRamBankSel[9]  & nRamBankSel[10] & nRamBankSel[11]
	 								&   nRamBankSel[12] & nRamBankSel[13] & nRamBankSel[14] & nRamBankSel[15] & !ShadowSel;

	// RAM addresses A0..A13 and data lines D0..D7 are wired to the CPU (via buffers on the IntegraB board)
	// RAM addresses A14..A18 are switched by the CPLD based on which RAM bank has been selected
	// ShadowSel is a 32k block based on Shadow RAM and Private RAM. A14 switches between the upper and lower bank.
	assign Ram_ADDRESS[14] = rD0 & !ShadowSel
								  | bbc_ADDRESS[14] & ShadowSel;
	assign Ram_ADDRESS[15] = rD1 & !ShadowSel;
	assign Ram_ADDRESS[16] = rD2 & !ShadowSel;
	assign Ram_ADDRESS[17] = rD3 & !ShadowSel;
	assign Ram_ADDRESS[18] = ShadowSel;

	// Logic to control RTC address and data strobe lines
	assign RTC_AS          = FE38_B && Phi2 && !RnW; // &FE38..B -> Address Strobe
	assign RTC_DS          = FE3C_F && Phi2;         // &FE3C..F -> Data Strobe

	// Logic to enable the data buffer.
	// Buffer needs to be enabled (logic low) when accessing onboard SWRAM, SWROM, Shadow RAM, Private RAM, or when writing data to registers &FE30..&FE3F
	assign nDBuf_CE     	  =  !SWRAddr & !ShadowSel & !FE3x
	 							  |  !nRomBankSel0_3 & !ShadowSel & !FE3x; // this line ensures the IntegraB data buffer not active when accessing off board SWROM


	//This data is latched when address is in the range FE30..FE33
	//rD0..rD3 are used to decode the selected SWROM bank
   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD0 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD0 <= bbc_DATA[0];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD1 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD1 <= bbc_DATA[1];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD2 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD2 <= bbc_DATA[2];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         rD3 <= 1'b0;
      end else if (!RnW && FE30_3) begin
         rD3 <= bbc_DATA[3];
      end
   end

	//PrvEn is used in conjunction with addresses in the range &8000..&AFFF to select Private RAM
   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvEn <= 1'b0;
      end else if (!RnW && FE30_3) begin
         PrvEn <= bbc_DATA[6];
      end
   end
 
	always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         MemSel <= 1'b0;
      end else if (!RnW && FE30_3) begin
         MemSel <= bbc_DATA[7];
      end
   end


	//This data is latched when address is in the range FE34..FE37
   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvS8 <= 1'b0;
      end else if (!RnW && FE34_7) begin
         PrvS8 <= bbc_DATA[4];
      end
   end
	
	always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvS4 <= 1'b0;
      end else if (!RnW && FE34_7) begin
         PrvS4 <= bbc_DATA[5];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         PrvS1 <= 1'b0;
      end else if (!RnW && FE34_7) begin
         PrvS1 <= bbc_DATA[6];
      end
   end

   always @(negedge Phi2 or negedge bbc_nRST) begin
      if (!bbc_nRST) begin
         ShEn <= 1'b0;
      end else if (!RnW && FE34_7) begin
         ShEn <= bbc_DATA[7];
      end
   end

endmodule
Last edited by KenLowe on Sun Dec 06, 2020 1:07 pm, edited 1 time in total.

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sat Dec 05, 2020 10:52 pm

Here's a photograph of my third V2 board with both RAM and RTC working on it.

The flying lead picks up Phi2 from the CPU and connects it to a clock input on the CPLD. This clock input was originally assigned as an output to the Chip Enable input of SWROM 14. In the next revision of the board the I/O will be re-assigned to correct this.

You may also notice a battery case containing a CR2032 battery which is connected to the board in place of the rechargeable Varta. That was to address the over voltage issue I was experiencing on the RTC VBat pin. Not sure if that's still an issue with this newer RTC, but regardless, I'll make that a permanent change in the next board revision. I'm also going to modify the CE of RTC so that it get's pulled high on loss of main power because I appear to be getting excessive battery drain with it permanently pulled low.

Other than that (and the supervisory IC issue I still need to look at), it's all looking pretty good now!

I maybe getting ahead of myself a bit here, but I was also thinking about adding a PLCC based 6522 to a future board revision so a MMFS solution could be added without tying up the User or Printer ports. Thoughts from anyone?
20201205_221831.jpg
It's looking better...

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Sun Dec 06, 2020 12:11 pm

I've re-instated the Supervisor IC with the watchdog hooked up to nRDS instead of A13, and that now also seems to be working just fine. I also soldered a different flying lead onto the battery carrier. This allows me to use a plug / socket arrangement for the temporary battery holder, so it's looking much neater.

Now I'm happy that the basic hardware is working, I went back to the CPLD, and switched back to using !Phi1 instead of Phi2, which allows me to get rid of that flying patch lead. Phi1 is not wired into a CPLD global clock input, so I was curious to know how the hardware would behave. To be very clear, this was just an experiment to satisfy my own curiosity, and the final board will most definitely have Phi2 wired directly into a global clock input, and that will be used in the logic. Much to my surprise, everything is working perfectly with !Phi1 in place of Phi2. So, the only patch I currently have on the board is in the supervisor watchdog circuit. Everything else is working pretty much as originally designed!

I've been doing quite a lot of testing with Lancelot, TIme & Magic & several adventure games produced with the awesome Ozmoo. These all give shadow and sideways RAM a good work out.

Main challenges along the way:
  • nWDS: I had forgotten to include the Shadow / Private RAM access in driving this signal. This prevented Shadow RAM from working correctly. It took me some time to figure this one out!
  • PRVSx: PRVS1 & PRVS8 were swapped. This is a long standing misprint in the original IntegraB user guide that I accidentally carried through to the CPLD logic
  • RTC: Don't rely on rubbish from China. Source from a reliable distributor. Lesson learned the hard way!
  • VBat: The RTC battery input was being fed with a voltage that was out of spec causing the IC to go into standby mode (I think)
Improvements for the next run of boards:
  • Connect Phi1 and Phi2 into global clock inputs. This will probably involve me rotating the CPLD IC through 90Deg on the circuit board to get the best layout
  • Connect the Supervisor IC watchdog to nRDS instead of A13
  • Tie the Supervisor IC Reset output into the RTC CE input so the RTC outputs are disabled when the beeb is powered off (I think I may need to invert the Reset signal, but I'll look into that later)
  • Reduce the address and data bus pull downs from 47k to 4k7
  • Ditch the battery charging circuit and associated Varta (or possibly make it optional), and use a non rechargeable CR2032 instead
Latest photo. Note that the 8 jumpers just above the CPU tell the CPLD to use the onboard RAM instead of the 8 ROM sockets on the IntegraB board. The DFS ROM in the top left hand corner of the board is currently being ignored. It can be paged back in by removing one of those 8 jumpers (and the beeb obviously then needs to be reset). The row of 16 jumpers (only 4 currently have jumpers installed) at the very top of the board are used to write enable the 16 RAM banks:
20201206_115811.jpg
Phi2 patch lead removed, and plug/socket arrangement in use for the temporary battery holder

User avatar
hoglet
Posts: 9799
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by hoglet » Sun Dec 06, 2020 2:22 pm

Thanks for the update - it's nice to see you getting closure on this!

User avatar
KenLowe
Posts: 1622
Joined: Mon Oct 18, 2004 5:35 pm
Location: UK
Contact:

Re: Help - Implementing Shadow RAM in CPLD

Post by KenLowe » Mon Dec 07, 2020 10:54 pm

hoglet wrote:
Sun Dec 06, 2020 2:22 pm
Thanks for the update - it's nice to see you getting closure on this!
Thanks Dave. I'm actually really pleased, because everything seems to be working perfectly now. The one thing I was a little bit worried about was getting RAM corruption on a power cycle, and battery drain if the computer was left depowered for a period, but neither of those have been happening. It's been very robust - albeit it's only been a couple of days.

I've got a few more of these V2 boards left from the first batch I ordered, so I might build a couple of them up and post them out to anyone who would be willing to give them an extended test. Ideally individuals who already have my V1 board and are familiar with its operation. That would also avoid me from having to ship the board out with the 40 pin extension header, which is a relatively expensive component. I'll need to get another few RTC chips first, though. If anyone (preferably UK based to limit shipping costs) is interested in testing, then please drop me a PM.

Post Reply

Return to “8-bit acorn hardware”