ROMulus the 2nd
ROMulus the 2nd
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 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 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 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
- 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 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 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 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
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: ROMulus the 2nd
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 ...
Nice looking kit!
Mike B.
Re: ROMulus the 2nd
560x192 is BW, when using 16 colors its only 160x192
Re: ROMulus the 2nd
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.
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.
Re: ROMulus the 2nd
After some more hardware and PCB checks I decided to populate the rest of the essential parts
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
Fortunately the AVR and the CPLD support a lot of programming cycles.
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
Re: ROMulus the 2nd
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. Cheers Peter
The following schematic already contains the bugfixes to these errors. Cheers Peter
Re: ROMulus the 2nd
So here comes the next piece of documentation, the WinCUPL design file of the CPLD
Certainly a lot of background is required to understand everything, but so far I did not spend enough time to make a decent documentation.
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];
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: ROMulus the 2nd
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.
Mike B.
Re: ROMulus the 2nd
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.
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.
Re: ROMulus the 2nd
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 The second page shows the CPU, RAM and the CPLD And the third page shows the MAX232 level shifter and the IO Bus expansion Port 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
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
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 The second page shows the CPU, RAM and the CPLD And the third page shows the MAX232 level shifter and the IO Bus expansion Port 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
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
Re: ROMulus the 2nd
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
Then it will disable the clock and assert reset
Now we can initialise the 65xxx system. For this we execute the following code
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
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.
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
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.
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
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
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
;
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
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
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