ROMulus the 2nd

For discussing the 65xx hardware itself or electronics projects.
Post Reply
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

ROMulus the 2nd

Post by cbscpe »

So I finally decided to go the PCB path. After the concepts have been tested with ROMulus the 1st on some breadboards I wanted to build something more durable. ROMulus the 2nd has all the features of the 1st but also has some enhancements. When finished it will (should be) able to emulate an Apple IIe including the double hires mode with 160 x 192 pixels and 16 colors. However due to the design you can convert the system into whatever you want. Everything is "configurable" within limits, that is as long as the CPLD design can be implemented in the CPLD and the given allocation of the PINs fits the design you're save. And as with all the ROMulus there is no ROM, there is only some RAM that emulates ROM, all depends on the CPLD design. It basically features

- A home-brew video controller using a ATmega1284P with 32kbyte dual-port video RAM and VGA output (560x480 pixels, this is due to the fact that I want to use the 7-bit wide original character sets of legacy systems)
- A PS/2 keyboard interface using the ATmega1284P using one of it's USART in synchronous mode
- Initial Machine Load of ROM images through the ATmega (as with the 1st you can have ROM images in flash or download images via XMODEM)
- A ATF1508AS CPLD which holds almost all of the glue logic (a 74HCT14 schmitt-trigger has been added to deglitch the PS/2 signals and a 74HCT573 has been added to support the 32kbyte video RAM via the ATMega1284P, as the CPLD does not provide enough pins)
- 512kbyte RAM

Here is a picture of the PCB
PCB
PCB
as ordered with dirtypcbs.

I'm slowly bringing up the system in several stages. The first stage was to check the CPLD Glue logic that emulates the 74HC166 from ROMulus the 1st
Controller, CPLD and Schmitt Trigger
Controller, CPLD and Schmitt Trigger
and also the first color mapping logic which is new in this version of the series. In this stage the internal RAM of the AVR was used as video RAM

Currently I have reached the state where the dual-port RAM and the address latch has been added and a stable VGA signal is created using the dual-port RAM as video RAM
plus Video RAM (DP-RAM) and Address Latch
plus Video RAM (DP-RAM) and Address Latch
the only missing parts now are the 512kbyte SRAM and the CPU.

Up to now the process was rather successful, although I had to make same smaller "corrections" to the PCB. But nothing what a Proxxon drill and vero-wire couldn't solve.

More to come

Cheers

Peter
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: ROMulus the 2nd

Post by barrym95838 »

cbscpe wrote:
... When finished it will (should be) able to emulate an Apple IIe including the double hires mode with 160 x 192 pixels and 16 colors ...
I think you meant to say 560 x 192.

Nice looking kit!

Mike B.
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

Re: ROMulus the 2nd

Post by cbscpe »

560x192 is BW, when using 16 colors its only 160x192
User avatar
cbmeeks
Posts: 1254
Joined: 17 Aug 2005
Location: Soddy-Daisy, TN USA
Contact:

Re: ROMulus the 2nd

Post by cbmeeks »

That's right. Because the Apple II is always generating B/W signals. But, when you run them through a color monitor, you get the classic NTSC artifacts.

The 160 pixels is about as fast as NTSC can change colors per pixel with minimal color clashing.

Anyway, awesome project.
Cat; the other white meat.
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

Re: ROMulus the 2nd

Post by cbscpe »

After some more hardware and PCB checks I decided to populate the rest of the essential parts
Fully populated PCB
Fully populated PCB
The missing MAX232 and the corresponding connector is for the RS-232 of the AVR, but currently I'm using a USB-TTL serial adapter and don't need the level shifter. As always software errors are more common than hardware errors and in this case I have to program the CPLD and the bootcontroller (the ATmega1284P) in parallel that makes it even worse. So I added some decent debugging output (in hardware of course) to the bus interface. Now step by step I eliminate the software errors :roll: Fortunately the AVR and the CPLD support a lot of programming cycles.
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

Re: ROMulus the 2nd

Post by cbscpe »

Seems that there weren't too many errors. The software is still not finished but at least I can load a ROM image and the SBC can take over control. At the moment I was able to load the Apple IIplus ROM image and write programs in Applesoft Basic. PS/2 interface works and 40-column Text Output as well. Now the rest is diligence work. Also so far the two errors in the PCB were really stupid. Both are related to the programming connectors. The AVR ISP interface had MOSI and MISO swapped and the JTAG interface had connected VTG (Vcc Target) to Pin 7 instead of Pin 4.

The following schematic already contains the bugfixes to these errors.
ROMulus2ndV2xrev1.pdf
(44.62 KiB) Downloaded 181 times
Cheers Peter
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

Re: ROMulus the 2nd

Post by cbscpe »

So here comes the next piece of documentation, the WinCUPL design file of the CPLD

Code: Select all

Name     ROMULUS2ND ;
PartNo   00 ;
Date     04.06.2016 ;
Revision V2 ;
Designer cbscpe ;
Company  privat ;
Assembly None ;
Location athome ;
Device   f1508ispplcc84;

/*
	2016-06-22	Peter Schranz
		Added some ideas for double hires
		splitted D7 into SSW read and D7
		Renamed SEL to GR
		Still missing is hires
	2016-06-04	Peter Schranz
		Instead of R11, R12 and R13 we map the different regions now
		to Banks 0 to 7, this will leave only very littel contingous
		extended RAM but on the other side it saves pins, product terms
		connections, also there is no reason to have extended RAM when
		using only the Apple IIe side
	2016-04-28	Peter Schranz
	This is a system that is based on the projects
		ROMulus1st
		AppleIIeV8

	It includes the following functions
	-	ROMulus ROM-less boot using blind-load (IML)
	-	All 128kbyte Apple IIe logic, i.e. softswitches RAM
		mapping and extended ROM
	-	IO ROM mapping
	-	Video Glue logic that replaces the 74HCT574, the 74HC166
		and the ANNUNCIATORS GAL22V10 of the AppleIIeV8
	Recode R16 generation. It seems the first version of the 24-bit
	version of the generation of R16 is not correct, so we take the
	version used in AppleIIeV8 that make sure this design fits, how-
	ever the result of the optimizer uses 2 level of foldback signals
	which is not optimal for high clock rates
	2016-05-21	Peter Schranz
	New version of R16 generation with 24-bit address support and
	only 1 level of foldback signals
*/

PROPERTY ATMEL {preassign = KEEP};
/*PROPERTY ATMEL {logic_doubling = ON};
/*PROPERTY ATMEL {cascade_logic = OFF};
/*PROPERTY ATMEL {fold = IOPAGE};*/
PROPERTY ATMEL {SOFT_BUFFER = IOPAGE};

/* $define ROMULUS1ST */

/* *************** CPU Interface **************************************/
PIN    48   = A0      ; /* CPU Address Bus                            */
PIN    49   = A1      ; /*                                            */
PIN    50   = A2      ; /*                                            */
PIN    51   = A3      ; /*                                            */
PIN    46   = A4      ; /*                                            */
PIN    34   = A5      ; /*                                            */
PIN    44   = A6      ; /*                                            */
PIN    45   = A7      ; /*                                            */
PIN    36   = A8      ; /*                                            */
PIN    35   = A9      ; /*                                            */
PIN    55   = A10     ; /*                                            */
PIN    56   = A11     ; /*                                            */
PIN    39   = A12     ; /*                                            */
PIN    58   = A13     ; /*                                            */
PIN    33   = A14     ; /*                                            */
PIN    60   = A15     ; /*                                            */
 
PIN    52   = D0      ; /* CPU Data Bus                               */
PIN    41   = D1      ; /*                                            */
PIN    40   = D2      ; /*                                            */
PIN    37   = D3      ; /*                                            */
PIN    57   = D4      ; /*                                            */
PIN    61   = D5      ; /*                                            */
PIN    63   = D6      ; /*                                            */
PIN    15   = D7      ; /*                                            */
 
PIN    17   = RW      ; /* CPU R/W Signal                             */
PIN     1   =!RES     ; /* System Reset                               */
PIN     2   = PHI2    ; /* System Clock                               */

/* *************** Video / Boot Controller Interface ******************/

/*
	The Video Interface is using a ATmega1248P which is used similarly
	to the AVR in the ROMulus 1st however there are some changes. Here
	is the usage from ROMulus 1st
	
	Port A		Connects to the CPLD Video Port and the lower address
				bits of the dual-port video RAM
	Port B		VPB, INP, KEY, IML, INH, !CE, !RES, SHLD
	Port C		Connects to the data bus of the dual-port video RAM
	Port D		RXD, TXD, DATA, BLANK, CLOCK, HSYNC, PHI2, LE
	Port E		VA7, VA8, VA9, VA10, !WE, !OE, SEL, VSYNC
	Port F		TEXT, MIXED, PAGE2, HIRES, 80COL, ALTCHAR, 80STO, DHIRES
	
	This CPLD makes changes to the following signals

	INP		is now RDV and reads the bits directly from the CPLD (Port F)
	KEY		is now WRK and writes the byte to the CPLD internally
	IML		is now WRC and is used to write controll signals to the CPLD
	
	SEL		is now added to the control signals internal to the CPLD and not
			on the 74HCT573 (Port E) and is renamed to GR (Graphics)
	WE		is now a latch in the CPLD
	OE		is no longer available
	
	SEL, WE and OE on PORT E are now used for VA12, 13, 14 of the 32kbyte
	video RAM.

	RDV		Active Low, Output Enable to read the video control bits
			like TEXT, GR, PAGE2, etc.
	WRK		Write Keyboard/Byte Buffer clock. The content of control bus
			data (V0..7) is written to the keyboard/byte buffer with the
			leading edge of the signal
	WRC		A system control register latch write enable signal. Active
			high.
	BLANK	Active Low, disables the color outputs. When high enables
			the color outputs Rx, Gx and Bx.
	
	The video controller can now read the video control bits of the
	Apple IIe (via RDV). Then it must set the system control signals
	and the internal logic. The video controller does this after he
	has displayed a full screen. The system control bits are
	[IML, VBL, WE, GR, HRES, CA, OA, TAPE].le = WRC;

	IML		Sets the Initial Machine Load mode, normally when set it allows
			the CPU to write the complete memory and reads are always
			directed to the keyboard/byte buffer. The video controller 
			controls PHI2 of the CPU manually and presents a boot load
			code to the CPU via the keyboard/byte buffer (blind load). 
			The video controller also controls RES of the CPU. So it can
			tell for every PHI2 cycle what the CPU expects and is thus
			able to send the reset vector and the instructions which 
			write the ROM image to the RAM. When cleared it normally write
			protects the ROM portion of the RAM
	VBL		is the video blank signal set during the non displayed lines
			can be used by the CPU
	WE		An extension of AVR ports to write enable the video RAM. 
			Actually this is not necessary for the system to work it
			only is used during development and debugging
	GR		When set activates the graphics mode
	HRES	High Resolution Graphics
	CA		Closed Apple
	OA		Open Apple
	TAPE	Tape

 */	
PIN     84  =!RDV     ; /* Control Bus Read Enable                    */
PIN     81  = WRC     ; /* System Control Write Enable                */
PIN      6  = WRK     ; /* Keyboardbuffer/Boot Loader Write Clock     */

PIN     67  = V0      ; /* Control Bus Data                           */
PIN     68  = V1      ; /*                                            */
PIN     70  = V2      ; /*                                            */
PIN     69  = V3      ; /*                                            */
PIN     73  = V4      ; /*                                            */
PIN     74  = V5      ; /*                                            */
PIN     76  = V6      ; /*                                            */
PIN     75  = V7      ; /*                                            */

PIN     83  = CLK     ; /*  Video Clock                               */
PIN     16  = INH     ; /*  Video Clock Inhibit                       */
PIN      5  = SHLD    ; /*  Shift=1 / Load=0 Video Shift Register     */
PIN     10  =!BLANK   ; /*  Video Blank input                         */

PIN     25  = BH      ; /* Video DAC Blue High                        */
PIN     27  = BL      ; /* Video DAC Blue Low                         */

PIN     18  = GH      ; /* Video DAC Green High                       */
PIN     20  = GM      ; /* Video DAC Green Medium                     */

PIN     29  = RH      ; /* Video DAC Red High                         */
PIN     28  = RM      ; /* Video DAC Red Medium                       */

/* *************** Memory Interface ***********************************/
PIN      4  =!RAM     ; /* Main RAM Enable                            */
PIN     54  =!VRAM    ; /* Video RAM Enable                           */
PIN     30  =!RAME    ; /* Extended RAM Enable                        */
PIN     77  = WE      ; /* Write Enable Video RAM                     */
 
PIN     80  =!MRD     ; /* Master Read                                */
PIN     79  =!MWR     ; /* Master Write                               */

PIN     31  =!IO65    ; /* 65xx Peripheral Enable                     */
PIN     65  =!IDE     ; /* Disk Enable                                */
PIN     64  =!IOBD    ; /* Another Peripheral Enable                  */
 
PIN     24  = R16     ; /*                                            */
PIN      8  = R17     ; /*                                            */
PIN     11  = R18     ; /*                                            */

/* *************** PINNODES    *********************/
PINNODE     = Q0      ; /* Language Card                              */
PINNODE     = Q1      ; /*                                            */
PINNODE     = Q2      ; /*                                            */
PINNODE     = Q3      ; /*                                            */
 
PINNODE     = BK0     ; /* Bank Address                               */
PINNODE     = BK1     ; /*                                            */
PINNODE     = BK2     ; /*                                            */
PINNODE     = BK3     ; /*                                            */
PINNODE     = BK4     ; /*                                            */
PINNODE     = BK5     ; /*                                            */
PINNODE     = BK6     ; /*                                            */
PINNODE     = BK7     ; /*                                            */
 
PINNODE     = KBD0    ; /* ASCII Keyboard register                    */
PINNODE     = KBD1    ; /*                                            */
PINNODE     = KBD2    ; /*                                            */
PINNODE     = KBD3    ; /*                                            */
PINNODE     = KBD4    ; /*                                            */
PINNODE     = KBD5    ; /*                                            */
PINNODE     = KBD6    ; /*                                            */
PINNODE     = KBD7    ; /*                                            */
 
PINNODE     = VSHFT0  ; /* ASCII Keyboard register                    */
PINNODE     = VSHFT1  ; /*                                            */
PINNODE     = VSHFT2  ; /*                                            */
PINNODE     = VSHFT3  ; /*                                            */
PINNODE     = VSHFT4  ; /*                                            */
PINNODE     = VSHFT5  ; /*                                            */
PINNODE     = VSHFT6  ; /*                                            */
PINNODE     = VSHFT7  ; /*                                            */
 
PINNODE     = TEXT    ; /* Annunciators                               */
PINNODE     = MIXED   ; /*                                            */
PINNODE     = PAGE2   ; /*                                            */
PINNODE     = HIRES   ; /*                                            */
 
PINNODE     = STO80   ; /* Softswitches  Store 80 column              */
PINNODE     = RAMRD   ; /*               RD AUX RAM                   */
PINNODE     = RAMWR   ; /*               WR AUX RAM                   */
PINNODE     = ALTZP   ; /*               ZP, STACK, LC AUX RAM        */
PINNODE     = C3ROM   ; /*               C3-Slot ROM                  */
PINNODE     = CXROM   ; /*               CX ROM                       */
PINNODE     = ALTCH   ; /*               Alternate Character Set      */
PINNODE     = COL80   ; /*               80-column display            */

PINNODE     = L8      ; /* Latched IO Slot Address                    */
PINNODE     = L9      ; /*                                            */
PINNODE     = L10     ; /*                                            */

PINNODE     = TAPE    ; /*  Simulation of TAPE Input                  */
PINNODE     = OA      ; /*  Open Apple Key                            */
PINNODE     = CA      ; /*  Closed Apple Key                          */
PINNODE     = HRES    ; /*  Select between Low-Res and High-Res       */ 
PINNODE     = GR      ; /*  Select between TEXT and Low-Res           */
PINNODE     = VBL     ; /*  Vertical Blank (VSYNC from Video Ctrl)    */
PINNODE     = IML     ; /*  Initial Machine Load                      */
 
PINNODE     = IOUDIS  ; /*                                            */
PINNODE     = DHIRES  ; /*                                            */

PINNODE     = I16      ; /*                                            */

PINNODE     = SLOTCK   ; /*                                            */

PINNODE     =  RR16;    /* if deasserted use ROMRD and ROMWR          */
PINNODE     =  VR16;    /* if asserted use PAGE2                      */
PINNODE     =  AR16;    /* if asserted ALTZP is used to assert R16    */
PINNODE     =  CR16;    /* if asserted then directly assert R16       */
PINNODE     =  AUX;     /* RAMWR and RAMRD preselected with RW        */

PINNODE        =  CSHFT6;
PINNODE        =  CSHFT5;
PINNODE        =  CSHFT4;
PINNODE        =  CSHFT3;
PINNODE        =  CSHFT2;
PINNODE        =  CSHFT1;
PINNODE        =  CSHFT0;

PINNODE        =  CLATCH0;
PINNODE        =  CLATCH1;
PINNODE        =  CLATCH2;
PINNODE        =  CLATCH3;
PINNODE        =  CLATCH4;
PINNODE        =  CLATCH5;

PINNODE        =  IOPAGE;
PINNODE        =  SSW;

/*
	IO Map
	
	C00x	Keyboard / Softswitches
	C010	KBDCLR
	C01x	Status
	C02x	
	C03x
	C04x	
	C05x	Annunciators
	C06x	Inputs
	C07x	
	C08x	Language Card
	C09x	IO65 65xx Peripheral
	C0Ax	IO65 65xx Peripheral
	C0Bx	IOBD Device
	C0Cx	IO65 65xx Peripheral
	C0Dx	IOBD Device 5
	C0Ex	IDE
	C0Fx	
 */

/*
	Field Definitions
*/
FIELD  ADDRESS   = [A15..0];
FIELD  IOADDR    = [A7..0];
FIELD  BANK      = [BK7..0];
FIELD  DATA      = [D7..0];
FIELD  CTRL      = [C2..0];
FIELD  VIDEO     = [V7..0];
FIELD  KBD       = [KBD7..0];
FIELD  VSHFT     = [VSHFT7..0];

/*
	Soft Buffer Signal
*/
IOPAGE    = !BK7 & !BK6 & !BK5 & !BK4 & !BK3 & !BK2 & !BK1 & !BK0
          &  A15 &  A14 & !A13 & !A12 & !A11 & !A10 & !A9  & !A8;
 
/*
	Bank Address Latch
*/
BANK.l    =  DATA.io;
BANK.le   = !PHI2;
 
/*
	The Keyboard buffer has two functions
	-	During IML it provides the bytes for the boot code
	-	In normal operation it acts as a keybaord input
		where bit7 indicates a key is waiting and can be
		cleared by the CPU by accessing the IO address $C010.
*/
KBD.d     =  VIDEO.io;
KBD.ck    =  WRK;
KBD7.ar   =  IOPAGE & IOADDR:[10] & PHI2;

/*
	Read the video status bits from the CPU
 */
VIDEO     =  [DHIRES, STO80, ALTCH, COL80, HIRES, MIXED, PAGE2, TEXT];
VIDEO.oe  =  RDV;

/*
	Video Shift register 
 */
VSHFT.ck  =  CLK;
VSHFT.ce  = !INH;

VSHFT.d   =  VIDEO.io   & !SHLD;

APPEND
VSHFT0.d  =  VSHFT0     &  GR  &  SHLD;

APPEND
VSHFT1.d  =  VSHFT1     &  GR  &  SHLD
          #  VSHFT0     & !GR  &  SHLD;

APPEND
VSHFT2.d  =  VSHFT2     &  GR  &  SHLD
          #  VSHFT1     & !GR  &  SHLD;

APPEND
VSHFT3.d  =  VSHFT3     &  GR  &  SHLD
          #  VSHFT2     & !GR  &  SHLD;

APPEND
VSHFT4.d  =  VSHFT4     &  GR  &  SHLD
          #  VSHFT3     & !GR  &  SHLD;

APPEND
VSHFT5.d  =  VSHFT5     &  GR  &  SHLD
          #  VSHFT4     & !GR  &  SHLD;

APPEND
VSHFT6.d  =  VSHFT6     &  GR  &  SHLD
          #  VSHFT5     & !GR  &  SHLD;

APPEND
VSHFT7.d  =  VSHFT7     &  GR  &  SHLD
          #  VSHFT6     & !GR  &  SHLD;

/*
	Double High Resolution support, together with INH
	every 4-bits the topmost 4 bits are converted to 
	a 6-bit colour value as in the icolors table of the
	low-resolution mode.
 */
CSHFT6.ck =  CLK;
CSHFT6.d  =  VSHFT0;
CSHFT5.ck =  CLK;
CSHFT5.d  =  CSHFT6;
CSHFT4.ck =  CLK;
CSHFT4.d  =  CSHFT5;

CSHFT3.ck =  CLK;
CSHFT3.d  =  CSHFT4;
CSHFT2.ck =  CLK;
CSHFT2.d  =  CSHFT3;
CSHFT1.ck =  CLK;
CSHFT1.d  =  CSHFT2;
CSHFT0.ck =  CLK;
CSHFT0.d  =  CSHFT1;

TABLE [CSHFT3..0] => [CLATCH5..0].d {
/*
	Color Mapping Table only produces 6bits. The icolors
	table has RRRGGGBB, we drop the least significant
	bit of R and G.

 */
 'h'0 => 'b'000000;  /* 0x00   Black       */
 'h'1 => 'b'110000;  /* 0xE0   Red         */
 'h'2 => 'b'000010;  /* 0x02               */
 'h'3 => 'b'100010;  /* 0x82               */
 'h'4 => 'b'000100;  /* 0x0C               */
 'h'5 => 'b'010101;  /* 0x49   Grey I      */
 'h'6 => 'b'000011;  /* 0x03   Blue        */
 'h'7 => 'b'001111;  /* 0x1F               */
 'h'8 => 'b'100000;  /* 0x84               */
 'h'9 => 'b'110100;  /* 0xEC               */
 'h'A => 'b'101010;  /* 0x92   Grey II     */
 'h'B => 'b'110110;  /* 0xEE               */
 'h'C => 'b'001100;  /* 0x1C   Green       */
 'h'D => 'b'111100;  /* 0xFC               */
 'h'E => 'b'001110;  /* 0x3E               */
 'h'F => 'b'111111;  /* 0xFF   White       */

}

CLATCH0.ck = CLK;
CLATCH1.ck = CLK;
CLATCH2.ck = CLK;
CLATCH3.ck = CLK;
CLATCH4.ck = CLK;
CLATCH5.ck = CLK;

CLATCH0.ce = INH;
CLATCH1.ce = INH;
CLATCH2.ce = INH;
CLATCH3.ce = INH;
CLATCH4.ce = INH;
CLATCH5.ce = INH;

/*
	The Video output is limit to 6-bit, 2 bits for each colour.
	The use of bits 7,6,4,3,1,0 as the source comes from the
	icolors table used in ROMULUS1st that had actually 8-bits
	(R:3-bit, G:3-bit, B:2-bit), so we can use the same table.
 */
RH        = !BLANK & !GR & !HRES & VSHFT7
          # !BLANK &  GR & !HRES & VSHFT7
          # !BLANK &        HRES & CLATCH5;

RM        = !BLANK & !GR & !HRES & VSHFT7
          # !BLANK &  GR & !HRES & VSHFT6
          # !BLANK &        HRES & CLATCH4;
          
GH        = !BLANK & !GR & !HRES & VSHFT7
          # !BLANK &  GR & !HRES & VSHFT4
          # !BLANK &        HRES & CLATCH3;
          
GM        = !BLANK & !GR & !HRES & VSHFT7
          # !BLANK &  GR & !HRES & VSHFT3
          # !BLANK &        HRES & CLATCH2;
          
BH        = !BLANK & !GR & !HRES & VSHFT7
          # !BLANK &  GR & !HRES & VSHFT1
          # !BLANK &        HRES & CLATCH1;
          
BL        = !BLANK & !GR & !HRES & VSHFT7
          # !BLANK &  GR & !HRES & VSHFT0
          # !BLANK &        HRES & CLATCH0;
          
/*
	System Control and Inputs. Note that these signals are not
	cleared on power up, it is the task of the video controller
	to initialise these system control bits.
 */
[IML, VBL, WE, GR, HRES, CA, OA, TAPE].l  = VIDEO.io;
[IML, VBL, WE, GR, HRES, CA, OA, TAPE].le = WRC;
 
/*
	CPU data read interface. The CPU can read various
	status bits and the keyboard buffer from the CPLD.
	The status bits can be read via D7 as in the Apple IIe.
	Bits 0..6 are directly connected to the lower 7 bits
	of the keyboard buffer. When IML is asserted the CPU
	just reads the keyboard buffer. This is used to initially
	load the ROM image. In this mode CPU reads always read
	the byte in the keyboard buffer and writes go to the RAM.
	
*/
[D6..0]   = [KBD6..0];

SSW       =  !A3 & !A2 & !A1 &  A0     & !Q3
          #  !A3 & !A2 &  A1 & !A0     &  Q0
          #  !A3 & !A2 &  A1 &  A0     &  RAMRD
          #  !A3 &  A2 & !A1 & !A0     &  RAMWR
          #  !A3 &  A2 & !A1 &  A0     &  CXROM
          #  !A3 &  A2 &  A1 & !A0     &  ALTZP
          #  !A3 &  A2 &  A1 &  A0     &  C3ROM
          #   A3 & !A2 & !A1 & !A0     &  STO80
          #   A3 & !A2 & !A1 &  A0     &  VBL
          #   A3 & !A2 &  A1 & !A0     &  TEXT
          #   A3 & !A2 &  A1 &  A0     &  MIXED
          #   A3 &  A2 & !A1 & !A0     &  PAGE2
          #   A3 &  A2 & !A1 &  A0     &  HIRES
          #   A3 &  A2 &  A1 & !A0     &  ALTCH
          #   A3 &  A2 &  A1 &  A0     &  COL80;


D7        = !IML & IOADDR:[00..0F] &  KBD7
          # !IML & IOADDR:[10..1F] &  SSW 
          # !IML & IOADDR:[60]     &  TAPE
          # !IML & IOADDR:[61]     &  OA
          # !IML & IOADDR:[62]     &  CA
          # !IML & IOADDR:[7E]     &  IOUDIS
          # !IML & IOADDR:[7F]     &  DHIRES
          #  IML                   &  KBD7;

[D7..0].oe = !IML & IOPAGE & IOADDR:[00..1F] & RW & PHI2
           # !IML & IOPAGE & IOADDR:[60..7F] & RW & PHI2
           #  IML                            & RW & PHI2;

/*
	Double Hires Support Flags. This is only for accuracy but not of
	any functionality.
*/
IOUDIS.CE = (IOPAGE & IOADDR:[7E..7F] & !RW);
IOUDIS.CK = !PHI2;
IOUDIS.D  =  A0;
IOUDIS.AR =  RES;
 
DHIRES.CE = (IOPAGE & IOADDR:[5E..5F] & !RW & IOUDIS);
DHIRES.CK = !PHI2;
DHIRES.D  =  A0;
DHIRES.AR =  RES;
/*
	Latch to hold the last IO Slot ROM accessed.
*/
SLOTCK    = BANK:[00] & ADDRESS:[C100..C7FF];
 
[L8..10].AR =  RES;
[L8..10].LE =  PHI2 & SLOTCK;
[L8..10].L  =  [A8..10];
 
/*
	Language Card
*/
[Q0..3].CK  = !PHI2;
 
[Q0..3].CE  =  IOPAGE & IOADDR:[80..8F];
 
[Q0..3].AR  =  RES;

Q0.D      =  A0  &  A1
          # !A0  & !A1;

Q1.D      =  A0  &  RW;

!Q2.D     =  A0  &  RW  &  Q1
          #  A0  & !Q2;

Q3.D      =  A3;

/*
	Softswitches
*/
STO80.CE  =  (IOPAGE & IOADDR:[00..01] & !RW);
STO80.CK  = !PHI2;
STO80.D   =  A0;
ST080.AR  =  RES;
 
RAMRD.CE  =  (IOPAGE & IOADDR:[02..03] & !RW);
RAMRD.CK  = !PHI2;
RAMRD.D   =  A0;
RAMRD.AR  =  RES;
 
RAMWR.CE  =  (IOPAGE & IOADDR:[04..05] & !RW);
RAMWR.CK  = !PHI2;
RAMWR.D   =  A0;
RAMWR.AR  =  RES;
 
CXROM.CE  =  (IOPAGE & IOADDR:[06..07] & !RW);
CXROM.CK  = !PHI2;
CXROM.D   =  A0;
CXROM.AR  =  RES;
 
ALTZP.CE  =  (IOPAGE & IOADDR:[08..09] & !RW);
ALTZP.CK  = !PHI2;
ALTZP.D   =  A0;
ALTZP.AR  =  RES;
 
C3ROM.CE  =  (IOPAGE & IOADDR:[0A..0B] & !RW);
C3ROM.CK  = !PHI2;
C3ROM.D   =  A0;
C3ROM.AR  =  RES;
 
COL80.CE  =  (IOPAGE & IOADDR:[0C..0D] & !RW);
COL80.CK  = !PHI2;
COL80.D   =  A0;
COL80.AR  =  RES;
 
ALTCH.CE  =  (IOPAGE & IOADDR:[0E..0F] & !RW);
ALTCH.CK  = !PHI2;
ALTCH.D   =  A0;
ALTCH.AR  =  RES;

/*
	Annunciators.
*/
TEXT.CE   =  (IOPAGE & IOADDR:[50..51]);
TEXT.CK   = !PHI2;
TEXT.D    =  A0;
TEXT.AR   =  RES;
 
MIXED.CE  =  (IOPAGE & IOADDR:[52..53]);
MIXED.CK  = !PHI2;
MIXED.D   =  A0;
MIXED.AR  =  RES;
 
PAGE2.CE  =  (IOPAGE & IOADDR:[54..55]);
PAGE2.CK  = !PHI2;
PAGE2.D   =  A0;
PAGE2.AR  =  RES;
 
HIRES.CE  =  (IOPAGE & IOADDR:[56..57]);
HIRES.CK  = !PHI2;
HIRES.D   =  A0;
HIRES.AR  =  RES;

/*
	Select Signals
 */
MRD       =  PHI2  &  RW;
MWR       =  PHI2  & !RW;

$ifndef ROMULUS1ST
RAM       =  BANK:[00] & ADDRESS:[0000..03FF] & !IML
          #  BANK:[00] & ADDRESS:[0C00..1FFF] & !IML
          #  BANK:[00] & ADDRESS:[4000..BFFF] & !IML
          #  BANK:[00] & ADDRESS:[C100..CFFF] & !IML &  RW			/* normal mode only allows read   */
          #  BANK:[00] & ADDRESS:[CF00..CFFF] & !IML & !CXROM		/* Each Slot has some private RAM */
          #  BANK:[00] & ADDRESS:[D000..FFFF] & !IML & !RW & !Q2	/* Language Card RAM Write        */
          #  BANK:[00] & ADDRESS:[D000..FFFF] & !IML &  RW			/* Language Card RAM/ROM Read     */
          #  BANK:[00] &                         IML & !RW 			/* Write enabled during IML       */
          #  BANK:[01..07];                                         /* Can always access upper BANKS  */

VRAM      =  BANK:[00] & ADDRESS:[0400..0BFF] & !IML
          #  BANK:[00] & ADDRESS:[2000..3FFF] & !IML;
 
RAME      =  BANK:[08..0F];

$endif
$ifdef ROMULUS1ST
RAM     =                          IML  & !RW
        #  ADDRESS:[0000..03FF] & !IML
        #  ADDRESS:[0C00..BFFF] & !IML
        #  ADDRESS:[C100..FFFF] & !IML  &  RW;

VRAM   =  ADDRESS:[0400..0BFF] & !IML
       #  ADDRESS:[0000..0FFF] &  IML  & !RW;

$endif
/*
	To emulate an Apple IIe the 512kbyte SRAM, that covers 8 memory banks,
	is mapped as following
	
	0000..BFFF	Using Bank 0 and 1 for MAIN and AUX
	C100..C2FF	Using Bank 0 and 1 for SLOTROM and CXROM controlled by CX
	C300..C3FF	Using Bank 0 and 1 for SLOTROM and CXROM controlled by C3
	C400..C7FF	Using Bank 0 and 1 for SLOTROM and CXROM controlled by CX
	C800..CFFF	Using Banks 0 to 7 for IOROM and CXROM
	D000..DFFF	Using Bank 0, 1, 2 and 3 for MAIN and AUX and BANK
				and Bank 4 for ROM
	E000..FFFF	Using Bank 0 and 1 for MAIN and AUX and Bank 4 for ROM

	To initialse the ROM images the boot loader can either change the memory
	map control signals via CPU code or it can just use absolutelong addresses
	to write directly to the appropriate Banks. 

 */

AUX       = !RW &  RAMWR
          #  RW &  RAMRD;

/*	RR16: R16 does not depend on RAMRD or RAMWR                                     */
RR16      =  ADDRESS:[0000..01FF]
          #  ADDRESS:[C000..FFFF];

/*	VR16: R16 depends on PAGE2 and hence not on RAMRD and RAMWR                     */
VR16      =  ADDRESS:[0400..07FF] &  STO80
          #  ADDRESS:[2000..3FFF] &  STO80  &  HIRES;

/*	AR16: R16 depends on ALTZP                                                      */
AR16      =  ADDRESS:[0000..01FF]
          #  ADDRESS:[D000..FFFF] & !RW   & !Q2
          #  ADDRESS:[D000..FFFF] &  RW   &  Q0;

/*  CR16: R16 in Slot ROM Region and in IO ROM Region for Slots 1,3,5,7             */
CR16      =  ADDRESS:[C100..C2FF] &  CXROM
          #  ADDRESS:[C300..C3FF] & !C3ROM
          #  ADDRESS:[C400..CFFF] &  CXROM
          #  ADDRESS:[C800..CFFF] & !CXROM & !L10 & !L9  &  L8    /* Slot 1         */
          #  ADDRESS:[C800..CFFF] &  C3ROM & !L10 &  L9  &  L8    /* Slot 3         */
          #  ADDRESS:[C800..CFFF] & !CXROM &  L10        &  L8;   /* Slot 5,7       */
/*  Combine all conditions to set R16                                               */
$ifndef ROMULUS1ST
R16       =  BANK:[00] & !RR16 & !VR16 &  AUX
          #  BANK:[00] &          VR16 &  PAGE2
          #  BANK:[00] &  AR16         &  ALTZP
          #  BANK:[00] &  CR16
          #  BK0;
/*  R17 is set for LC Card Bank 2 and for IO ROM Banks in C8 region for slots 2,3,6,7*/
R17       =  BANK:[00] &  ADDRESS:[D000..DFFF] & !RW  & !Q2  &  Q3
          #  BANK:[00] &  ADDRESS:[D000..DFFF] &  RW  &  Q0  &  Q3
          #  BANK:[00] &  ADDRESS:[C800..CFFF] & !CXROM & !L10 &  L9  & !L8    /* Slot 2         */
          #  BANK:[00] &  ADDRESS:[C800..CFFF] &  C3ROM & !L10 &  L9  &  L8    /* Slot 3         */
          #  BANK:[00] &  ADDRESS:[C800..CFFF] & !CXROM &  L10 &  L9           /* Slot 6,7       */
          #  BK1;
/*  R18 is set for D0 to F8 ROM and for IO ROM Banks in C8 region for slots 4-7      */
R18       =  BANK:[00] &  ADDRESS:[C800..CFFF] & !CXROM &  L10                 /* Slot 4,5,6,7   */
          #  BANK:[00] &  ADDRESS:[D000..FFFF] &  RW  & !Q0
          #  BK2;

$endif ROMULUS1ST
$ifdef ROMULUS1ST
[R18..16] = 'b'000;
$endif
/*
	IO Select
	
	IO65	is intended for 65xx peripherals, 65xx peripherals normally
			have two chip select a negative and a positive logic. IOB
			is connected to the negative active CS and the positive active
			CS is connected to A4,A5,A6. IOB as asserted only for three
			ranges where only one of these three address bits is high.
	IDE		is a general IO, primary purpose is a CFA mass storage.
 */
IO65      =  IOPAGE & IOADDR:[90..9X]
          #  IOPAGE & IOADDR:[A0..AX]
          #  IOPAGE & IOADDR:[C0..CX];
              
IDE       =  IOPAGE & IOADDR:[E0..EF];

IOBD      =  IOPAGE & IOADDR:[B0..BX]
          #  IOPAGE & IOADDR:[D0..DX];
Certainly a lot of background is required to understand everything, but so far I did not spend enough time to make a decent documentation.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: ROMulus the 2nd

Post by barrym95838 »

My Apple 2 background was immediately useful in understanding what you are trying to do, even though I know next to nothing about WinCUPL. Nice work!

Mike B.
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

Re: ROMulus the 2nd

Post by cbscpe »

Although the CPLD worked for Apple II and Apple II plus ROM images the Apple IIe ROM image only partially worked, e.g. the 80-column mode was not working as the CX ROM mapping was not correct.
ROMULUS2NDV2.txt
Updated CPLD design file with correct CX ROM mapping
(27.66 KiB) Downloaded 170 times
Now this design file supports the CX ROM Mapping and 80-column text mode works. The 65SC816 system, with no devices attached to the bus except for the debugging hardware, runs at 11MHz and is stable.
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

Re: ROMulus the 2nd

Post by cbscpe »

Here some further information to my ROMulus project. In the past two weeks I was working on the AVR code and on other projects as well. The hardware now runs the Apple IIe system check successfully. At least I get the "SYSTEM OK" page after the systems self test run (that's when you reset the system with the solid apple key pressed). This self-test checks the built-in IO and the memory.

During the setup of the hardware, as I already mentioned, I found two "bugs" in the PCB layout. One was a missing connection to VCC on the JTAG connector in pin 4 and the other was that I swapped pins 1 and 4 on the ISP header for the AVR processor. Here is now the schematic with the 2 errors already fixed.

The first page shows the dual-port RAM and the AVR with the additional glue logic which acts as Video Controller, PS/2 Interface and the boot controller
ROMulus2ndV2xrev1-p1.pdf
Schematic Page 1
(21.89 KiB) Downloaded 163 times
The second page shows the CPU, RAM and the CPLD
ROMulus2ndV2xrev1-p2.pdf
Schematic Page 2
(18 KiB) Downloaded 156 times
And the third page shows the MAX232 level shifter and the IO Bus expansion Port
ROMulus2ndV2xrev1-p3.pdf
Schematic Page 3
(19.21 KiB) Downloaded 154 times
There are two 8-bit paths to the CPLD, one is the SBC data-bus which goes into the CPLD and one is the address/control bus from the AVR to the CPLD. At startup the AVR sets the IML bit in the CPLD which causes the memory map to be slightly different. First all CPU reads go to the so called keyboard buffer and the memory map is flat. So only 512kbyte of RAM which is selected for write cycles. The AVR controls not only the IML bit but also can write to the keyboard buffer and controls CPU RESET and PHI2.

After the AVR has set IML it will assert reset and the manually control PHI2 so the W65C816 gets its required two PHI2 cycles with reset asserted to initiate a reset sequence. Then the AVR de-asserts reset and continues to manually control PHI2. Manually controlling PHI2 means it sets and resets the PHI2 level using set bit and clear bit IO instructions. As the W65C816 is a static CPU toggling of PHI2 must not occur at a given rate. Even though this would be not a big issue. By counting the cycles the AVR generates he exactly nows when the W65C816 reads the vector and the subsequent instructions. The absolute value of the reset vector is not important at all, because once the reset vector has been sent the AVR will then feed the W65C816 with a continuous loop of the following instructions

Code: Select all

     lda   #<data>
     stal  <absolutelongaddress>
     jmp  $300
the AVR will continue to send the above loop until all memory locations that are later ROM locations have been updated with the correct <data>.

Then the AVR will perform a second reset cycle. Only this time IML will be reset and the CPLD will now activate a memory mapping that matches the requirements, in my case a mapping which mimics a Apple IIe. You can of course you can implement whatever you need. Also the AVR now no longer manually controls PHI2 but rather programs the output used for PHI2 (OC2B) to generate a PWM signal of the desired clock speed. The fastest PHI2 clock that the AVR can generate is 1/2 the AVR clock speed, in my case 11MHz. But you can also generate any rate that is compatible with the PWM output signal generator and the best is it does not even have be be symmetric if you need that. Using a 8-bit counter the clock speed can go down to approx 100kHz. Very handy in case you want to test hardware so you can see everything in slow motion.

Once the second reset cycle has been executed the AVR will then start to generate the video signal and activates the PS/2 interface. The keyboard buffer used to boot the SBC is now used to send the PS/2 codes or ASCII keys (whatever you need) to the SBC. With the CPLD implementing the correct hardware you can read the keyboard from the W65C816.

The whole boot process is controlled via the serial interface of the AVR using USART0. At the moment I have to type in the commands that perform all the above steps. But there is also the option to save a initial sequence of commands in the EEPROM of the AVR that is executed whenever the AVR is reset.

The video controller uses a dual-port RAM, that's my lazy solution for video signal generation. The AVR is not the best video controller, but with some tricks (memory mapping as in Apple IIe) you can create everything from a simple text display, a low-res colour display (160 pixels wide with up to 480 lines) up to a 640x480pixel BW signal. As long as you provide enough dual-port RAM.

The system features also a small IO bus. The IO bus only brings out the signal as show in page 3 of the schematic. It has enough signals to address a page (256bytes) to act as IO page and is only intended to be used as IO expansion. Plans exist for a 4-channel USART (using one of those famous chips that BDD always praises) and a 8-bit CF-Card interface. The bus is breadboard friendly so you can test your IO separately.

Of course I have already come up with a list of items I would do different. But for now the system does for what it was initially designed for

Cheers

Peter
User avatar
cbscpe
Posts: 491
Joined: 13 Oct 2013
Location: Switzerland
Contact:

Re: ROMulus the 2nd

Post by cbscpe »

I'm watching the thread about the 3 chip design and the challenges to load an initial image to the 6502 system using a minimal count of a controller with great interest. So I take the time to elaborate a little more on the boot loader as it is implemented in ROMulus the 2nd and in principal in the 1st as well. Although this method will not fit into 3 chips a minimal version will at least fit into a 4 chip design: CPU, RAM, MCU, GLUE and uses a reasonable count of PINs. Depending on the requirements the GLUE will fit into a SPLD (GAL16V8 or GAL22V10) in my case, as GLUE does much more, the logic is part af a CPLD (ATF1508). I recommend that you have a look at the design file already attached to this thread.

There are the following signals that are controlled by the AVR

!RES this pin is constatly set to 0. Instead of de-asserting !RES the AVR switches between input and output so it is rather a open drain output and requires a pull-up, the advantage is that you can have a switch in parallel

PHI2 this pin uses OC2B of the AVR used here. Depending on the mode the AVR controll program either toggles the state manually using sbi and cbi instructions ore it activates Timer 2 to create a steady PHI2 clock

IML this signals to the CPLD (or whatever glue logic you use) which memory decoding scheme shall be active. When all reads from the 65C816 are directed to the internal byte buffer of the CPLD and all writes go to the memory. Memory is then addressed linearly as one 512kbyte RAM covering the first 8 banks. Note that IML is implemented as a bit in the internal control byte of the CPLD. The control byte can be written using WRC clock

WRK this signal latches the value on PORTA into the internal byte buffer of the CPLD

PORTA this is the data port of the AVR, in this design it connects to the CPLD to write internal registers, one of these is the byte register which can be read by the 65xxx

If you use this method for a minimal system, then you typically will just connect PORTA to the databus and of course you need also to add some instructions to control the direction of the PORTA when the CPU performs a write cycle. Using a PIC controller with a parallel port this could also be handled in the GLUE logic as the PORT of the PIC in this mode can be tri-stated. Or you could add a buffer between the MCU and the data bus. In any case this design in a minimal setup would use 11 pins of the MCU to be connected to the system: RES, PHI2, IML and D0..7. Of course much more pins than in the 3 chip design challenge but very few when compared to solutions that connect all bus signals to the MCU. If the pin count is critical the data bus could also be connected via a shift register, buth this will then make the system at least a 5 chip design. But I think 11 pins is quite good and there are no pull-up/downs on the databus and hence the system is capable of higher clock rates, in my case 11MHz.


At the beginning the AVR initialises the ports and starts in a known state with IML set in the CPLD control register

Code: Select all

;--------------------------------------------------------------------------
;
;	PORTA	A0..A7
;
;	Multiple Purpose Output Port, this port is connected to the CPLD to 
;	the address lines of the DPRAM and to the upper video RAM address
;	latch. 
;
	out		PORTA, ff
	out		DDRA, ff
;--------------------------------------------------------------------------
;
;	SYSCTL: This is a register that holds the current value of the CPLD control register
;
;	These flags are used to control the 65C816 system.
;
;	IML, VBL, WE, GR, SHFT, CA, OA, TAPE
;
.set	TAPE	= 0		;	Simlulate TAPE input
.set	OA		= 1		;	Open Apple Key
.set	CA		= 2		; 	Closed Apple Key
.set	SHFT	= 3		;	Shift Key
.set	GR		= 4		;	Graphics
.set	WE		= 5		; 0=Write Enable RAM
.set	VBL		= 6		;	Vertical Blank
.set	IML		= 7		; 1=Set Initial Machine Load
;
;
;
	ldi		temp, (1<<IML) | (1<<WE)
	out		PORTA, temp
	nop
	sbi		PORTB, WRC
	cbi		PORTB, WRC		; Latch Control Bits into CPLD
	in		SYSCTL, PORTA	; keep a copy
Then it will disable the clock and assert reset

Code: Select all

;--------------------------------------------------------------------------
;
;	PORTB	VPB, RDV, WRK, WRC, CE, RES, SHLD
;
.equ	VPB	= 0			; Vector Pull from 65xxx
.equ	RDV	= 1			; Read Video Control bits, active low!
.equ	WRK	= 2			; Write Byte Buffer/Keyboard Clock normally high
.equ	WRC = 3			; Write Control Bits Latch Enable normally low
.equ	INH	= 4			; Inhibit Video Pixel Clock OC0B
.equ	CE	= 5			; Video RAM Chip Enable
.equ	RES	= 6			; 65xxx reset
.equ	SHLD= 7			; SHLD video shift register connected to OC3B
;
;	Reset pin is set low and normally is configured as input. The normal
;	pull-up on the reset line will pull the signal high. To activate
;	reset we just set the pin as output which will pull the line low.
;
#define RESETPIN	DDRB, RES
;
	ldi		temp, (1<<RDV) | (1<<WRK) | (0<<WRC) | (1<<CE)
	out		PORTB, temp
	ldi		temp, (1<<RDV) | (1<<WRK) | (1<<WRC) | (1<<INH) | (1<<CE) | (1<<SHLD)
	out		DDRB, temp	
Now we can initialise the 65xxx system. For this we execute the following code

Code: Select all


imlprepare:
;
;	Stop the clock
;
	cbi		PORTD, PHI2		; Make sure we and with PHI2=Low
	sts		TCCR2B, zero	; Stop the timer
	sts		TCCR2A, zero
	sts		OCR2A, zero
;
	sbi		RESETPIN
;
;	After Reset is asserted (pulled low) the 65816 requires two
;	full PHI2 cycles to reset.
;
	sbi		PORTD, PHI2		; Note that consecutive sbi/cbi
	cbi		PORTD, PHI2		; create a clock requency of 4 AVR
	sbi		PORTD, PHI2		; cycles in our case 5.5MHz.
	cbi		PORTD, PHI2
	sbi		PORTD, PHI2
	cbi		PORTD, PHI2
	sbi		PORTD, PHI2
;
;	De-assert Reset when PHI2 is high so the 65816 will detect
;	the rising edge of reset at the next falling edge of PHI2
;
	cbi		RESETPIN
	nop
	nop
	out		PORTA, SYSCTL
	sbi		PORTA, IML
	sbi		PORTB, WRC
	cbi		PORTB, WRC		; Latch Control Bits into CPLD
	in		SYSCTL, PORTA
	cbi		PORTD, PHI2		; this for some reason does not
							; detect reset being de-asserted
;
;	It seems that the number of cycles after a reset is not well
;	and accurately documented in the W65C816 manual from WDC. How-
;	ever it is in line with the Synertek manual of the 6502
;
;		http://archive.6502.org/datasheets/synertek_hardware_manual.pdf
;
;	which states that after RESET is de-asserted (high) the 6502 will
;	delay 6 cycles and then fetch the program counter, so we wait
;	6 cycles before emitting the start address of IML.
;
	sbi		PORTD, PHI2
	cbi		PORTD, PHI2		; This detects that reset is de-asserted
	sbi		PORTD, PHI2
	cbi		PORTD, PHI2		; Cylce 1
	sbi		PORTD, PHI2
	cbi		PORTD, PHI2		; Cylce 2
	sbi		PORTD, PHI2
	cbi		PORTD, PHI2		; Cylce 3
	sbi		PORTD, PHI2
	cbi		PORTD, PHI2		; Cylce 4
	sbi		PORTD, PHI2
	cbi		PORTD, PHI2		; Cylce 5
	ret
;
Now the 65xxx processor is fully initialsed. The next the CPU expects is the reset vector and instructions. So we provide the necessary data. A small subroutine is used to place a byte into the byte buffer and strobe PHI2

Code: Select all

imlbyte:
	out		PORTA, temp		; Set value
	cbi		PORTB, WRK		; Reset WRK
	sbi		PORTB, WRK		; Load with leading edge
	sbi		PORTD, PHI2		; PHI2 = high
	nop
	nop
	nop
	cbi		PORTD, PHI2		; PHI2 = low
	ret
The following routine will take a ROM image in flash and copies it to the RAM address that late is the ROM. It expects the pointer Z to point the the flash image with the 65C816 ROM image. X is expected to be setup with the starting address of the ROM image as seen by the 65C816. In our case the ROM image must be copied into BANK 0 and BANK 4 depending on the value in X. This of course depends on how the CPLD maps the memory addresses. At the moment this routine just copies a ROM image from the starting address up to $FFFF. Different to ROMulus the 1st I now use the store absolute long instruction so I can write to the complete 24-address range of the 65C816. As this works as well in emulation mode I don't need to switch into native mode here. The loop starts with sending an address. When entered first this is the time when the 65C816 expects the address from the reset vector.

Code: Select all

wloop:
;
	ldi		temp, 0x00			; The first time we need to provide
	rcall	imlbyte
;
	ldi		temp, 0x03			; a RESET vector, any address will do so
	rcall	imlbyte				; we use the same address as in the JMP.
;
	ldi		temp, LDA_			; Load <immediate>
	rcall	imlbyte
;
	lpm		temp, Z+			; next byte from ROM image
	rcall	imlbyte
;
 	ldi		temp, STAL_			; Store <absolutelong>
;	ldi		temp, STA_			; Store <absolute>
	rcall	imlbyte
;
	mov		temp, xl			; to the current pointer
	rcall	imlbyte
;
	mov		temp, xh			; of the ROM image destination
	rcall	imlbyte
;
	mov		temp, zero			; CX ROM is in Bank 0
	cpi		xh, 0xD0
	brlo	wbank4
	ldi		temp, 0x04			; D0..F8 ROM is in Bank 4
wbank4:
	rcall	imlbyte
;
	ldi		temp, 0xff			; the write cycle, the value is not
	rcall	imlbyte				; relevant
;
	ldi		temp, JMP_			; Jump to start of loop
	rcall	imlbyte				; 
								; 
	adiw	xh:xl, 1			; Next ROM destination address
	brne	wloop				; if not overflow to 0 then continue
Now we have loaded the ROM image to the memory section that later will be mapped as ROM and typically will be write protected. To activate the ROM we first stop the clock, clear IML, assert RESET and the start the clock

Code: Select all

;
; Toggle IML in the control byte of the CPLD
;
imliml:
	sbi		GPIOR0, LOCKA
	out		PORTA, SYSCTL
	sbi		PINA, IML
	sbi		PORTB, WRC
	cbi		PORTB, WRC		; Latch Control Bits into CPLD
	in		SYSCTL, PORTA
	cbi		GPIOR0, LOCKA
	ret
;
; Start the clock, the value in a1l is set to the desired rate
;
imlclock:
	lds		temp, a1l
	tst		temp
	breq	imlstop
	ori		temp, 0x01		; 1 = 11MHz, 0x14 is ~1MHz, 0xC8 is ~ 100kHz
	sts		OCR2A, temp
	lsr		temp
	sts		OCR2B, temp
	ldi		temp, (1<<WGM22) | (0<<CS22) | (0<<CS21) | (1<<CS20)
	sts		TCCR2B, temp
	ldi		temp, (0<<COM2A1) | (0<<COM2A0) | (1<<COM2B1) | (1<<COM2B0) | (1<<WGM21) | (1<<WGM20)
	sts		TCCR2A, temp
	ret
The AVR must wait at least 2 clock cycles before de-asserting RESET. As IML has been cleared the memory mapping is switched to the normal SBC layout and the ROM image in RAM mapped to the upper addresses (in our case $C100..FFFF). Once RESET has been de-asserted the CPU will restart using the "ROM" image.
Post Reply