6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 16, 2024 1:06 pm

All times are UTC




Post new topic Reply to topic  [ 28 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sun Jul 19, 2015 3:17 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 491
Location: Switzerland
Hi,

several times there have been topics regarding bootstrapping a 6502 (or other systems) and the issues regarding slow ROMs in fast systems. Currently I have solved that using a DP-RAM that is used to bootstrap the 6502 and at the same time is the frame buffer for the VGA output.

But now I wanted to make a system without a video controller and with much less components. So I came up with the following solution.
Attachment:
File comment: CPU, Memory, Decoder and AVR
bootstrap-design.pdf [24.75 KiB]
Downloaded 233 times


Note that this is only a concept. Before I jump into this I first wanted to check if this really is feasible or if there is something that is obviously wrong or will not work.

The memory decoder is a simple decoder that supports two memory maps selected with IML (short form for Initial Machine Load). When IML is Low addresses $0000 to e.g. $BFFF will select the RAM for read and writes, addresses $C000..$C0FF decode to one of the IO select signals and for addresses $C100..$FFFF selects the RAM only for read accesses. When IML is High the RAM is only selected for write cycles, but not only for $0000..$BFFF but as well for $C100..$FFFF. Bootstrap is achieved via the AVR that controls RESET and PHI and during startup makes the 6502 think that he reads a ROM image, when in fact the AVR just emits the bytes that would be expected.

Here is the AVR code I have written so far for that purpose.

Code:
;
;   Inject a ROM loader loop
;
;
;   0300-   A9 00       LDA   #$00
;   0302-   8D AA AA    STA   $AAAA
;   0305-   4C 00 03    JMP   $0300
;

.def   zero   r2
.def   ff   r3
.def   temp   r17


.equ   LDA   0xA9
.equ   STA   0x8D
.equ   JMP   0x4C
.equ   PHI2   3         
.equ   RESET   1
.equ   IML   2         ; Initial machine load
.equ   ROMSTART   0xD000      ; Or whereever the 6502 ROM starts
;--------------------------------------------------------------------------
;
;   Initialization of AVR
;
reset:
   clr   zero
   ldi   temp, 0xff
   mov   ff, temp

   ldi
   cbi   PORTB, PHI2
   sbi   DDRB, PHI2      ; PHI2 is output

   cbi   DDRB, RESET
   cbi   PORTB, RESET      ; Let the pull-up do it's job

   sbi   DDRD, IML
   ldi   zl, low(2*romimage)
   ldi   zh, high(2*romimgea)
   ldi   xl, low(ROMSTART)
   ldi   xh, high(ROMSTART)
   
   sbi   PORTD, IML      ; Activate boot mode decoder
;--------------------------------------------------------------------------
;
;
;
   sbi   DDRB, RESET      ; Activate Reset

   sbi   PORTB, PHI2      ; Generate some PHI2 cycles
   nop            ; Need at least 2 cycles
   nop
   nop
   cbi   PORTB, PHI2
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop
   cbi   PORTB, PHI2
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop
   cbi   PORTB, PHI2
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop
   cbi   PORTB, PHI2
   nop
   nop
   nop
   sbi   PORTB, PHI2
   cbi   DDRB, RESET      ; Release Reset, when a positive
   nop            ; Edge is detected the 6502 will
   nop            ; start a reset cycle
   nop
;--------------------------------------------------------------------------
;
;   The eight reset cycles
;
   cbi   PORTB, PHI2      ; Cycle 0
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop
   
   cbi   PORTB, PHI2      ; Cycle 1
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop

   cbi   PORTB, PHI2      ; Cycle 2
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop

   cbi   PORTB, PHI2      ; Cycle 3
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop

   cbi   PORTB, PHI2      ; Cycle 4
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop

   cbi   PORTB, PHI2      ; Cycle 5
   nop
   nop
   nop
   sbi   PORTB, PHI2
   nop
   nop
   nop

   jmp   setv         ; Cycle 6 and 7 read the reset
               ; vector value which is the same
               ; as the JMP will loop to, so use
               ; this code.
;--------------------------------------------------------------------------
;
;   Generate one cycle: Opcode LDA immediate
;
;   
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;
   ldi   temp, LDA      ;   Get Opcode
   out   PORTC, temp      ;   Set Buffer
   cbi   PORTD, 6      ;   and
   sbi   PORTD, 7      ;    Set PORT bits
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;    Enable buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop
;--------------------------------------------------------------------------
;
;   Generate one cycle: Immediate Value
;
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;   
   
   lpm   temp, Z+      ;   Get immediate value
   out   PORTC, temp      ;   Set Buffer
   cbi   PORTD, 6      ;   and
   sbrc   temp, 6
   sbi   PORTD, 6
   cbi   PORTD, 7      
   sbrc   temp, 7
   sbi   PORTD, 7      ;    Set PORT Bits
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;   Enable Buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop

;--------------------------------------------------------------------------
;
;   Generate one cycle: Opcode STA absolute
;
;   
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;
   ldi   temp, STA      ;   Get Opcode
   out   PORTC, temp      ;   Set Buffer
   cbi   PORTD, 6      ;   and
   sbi   PORTD, 7      ;    Set PORT bits
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;    Enable buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop
;--------------------------------------------------------------------------
;
;   Generate one cycle: low byte address
;
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;   
   
   out   PORTC, xl      ;   Get Low Byte
   cbi   PORTD, 6      ;   and
   sbrc   xl, 6
   sbi   PORTD, 6
   cbi   PORTD, 7      
   sbrc   xl, 7
   sbi   PORTD, 7      ;    Set PORT Bits
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;   Enable Buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop
;--------------------------------------------------------------------------
;
;   Generate one cycle: high byte address
;
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;   
   
   out   PORTC, xh      ;   Get Low Byte
   cbi   PORTD, 6      ;   and
   sbrc   xh, 6
   sbi   PORTD, 6
   cbi   PORTD, 7      
   sbrc   xh, 7
   sbi   PORTD, 7      ;    Set PORT Bits
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;   Enable Buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop
   
;--------------------------------------------------------------------------
;
;   Generate one cycle: write byte to SRAM
;
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
   nop
   nop
   nop
   nop
   sbi   PORTB, PHI2      ;   PHI2 = High
   nop            ;    Give CPU some time
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   adiw   xh:xl, 1
   breq   done         ;   Stop after writing to $FFFF
;--------------------------------------------------------------------------
;
;   Generate one cycle: Opcode JMP absolute
;
;   
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;
   ldi   temp, JMP      ;   Get Opcode
   out   PORTC, temp      ;   Set Buffer
   sbi   PORTD, 6      ;   and
   cbi   PORTD, 7      ;    Set PORT bits
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;    Enable buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop
;--------------------------------------------------------------------------
;
;   Generate one cycle: low byte address of $0300
;
setv:
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;   
   
   out   PORTC, zero
   cbi   PORTD, 6
   cbi   PORTD, 7
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;   Enable Buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop
;--------------------------------------------------------------------------
;
;   Generate one cycle: high byte address of $0300
;
   cbi   PORTB, PHI2      ;   PHI2 = Low
   out   DDRC, zero      ;   Disable buffer
   out   DDRD, zero      ;
;   
   ldi   temp, 0x03   
   out   PORTC, temp      ;   Get Low Byte
   cbi   PORTD, 6      ;   and
   cbi   PORTD, 7      
   sbi   PORTB, PHI2      ;   PHI2 = High
   out   DDRC, ff      ;   Enable Buffer
   out   DDRD, ff
   nop            ;    Give CPU some time
   nop
   nop
   jmp   loop
;--------------------------------------------------------------------------
;
;   Finished loading bootrom
;
done   cbi   PORTB, PHI2      ;

;--------------------------------------------------------------------------
;
;   Now the upper memory should be filled with the ROM image
;
;

   cbi   PORTD, IML      ; Activate normal memory decocder
   sbi   DDRD, RESET      ; Assert RESET
;
;   Now we can programm Timer 2 to act as source for PHI2
;   the maximum clock frequency we can achieve is AVRCLK/2
;   a modern AVR supports a clock up to 20MHz, you can easily over
;   clock it to 25MHz other options would use an external clock
;   that would have to be multiplexed by the GAL using IML as select
;
;
;   Timer is started in CTC mode with TOP=OCR2A and no prescaler
;   this gives an output of AVRCLK/2 as PHI2 for the 6502
;
   out   OCR2A, zero
   ldi   temp, (COM2A1<<0) | (COCM2A0<<1) | (COM2B1<<0) | (COCM2B0<<1) | (WGM21<<1) | (WGM20<<0)
   out   TCCR2A, temp
   ldi   temp, (WGM22<<0) | (CS22<<0) | (CS21<<0) | (CS20<<1)
   out   TCCR2B, temp
;
;   Now the real reset starts, so we need to wait at least 2 PHI2 cycles
;   before we de-assert RESET
;
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   cbi   DDRD, RESET      ; De-Assert RESET
;
;   Now the 6502 executes the normal RESET with the vector in the loaded
;   ROM Image.
;
   ....            ; And the AVR can do what ever we
   ....            ; want him to do.



The trick here is not to control the address bus. Instead after a reset of the AVR we control the PHI2 via Software and put out the bytes the 6502 would read when we really had a ROM. The ROM we present is rather small, it is a RESET vector and 3 instructions that just write immediate data to the memory in a loop. As the RAM is write enabled this loop can now load a ROM image. After the image is loaded IML is de-asserted and the 6502 is RESET and start the ROM with it's own reset vector


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 19, 2015 5:54 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10980
Location: England
I think the broad idea is sound - and simple - and a good idea. But I haven't reviewed your code or anything.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 19, 2015 8:50 pm 
Offline
User avatar

Joined: Wed Feb 13, 2013 1:38 pm
Posts: 589
Location: Michigan, USA
cbscpe wrote:
Note that this is only a concept. Before I jump into this I first wanted to check if this really is feasible or if there is something that is obviously wrong or will not work.

You should be able to get this to work. It seems similar to the "blind loader" method I implement using a PIC in my designs (which include the address decoder function in the PIC as well).

I've included example loader code below which copies a pseudo ROM image from PIC flash memory at $E000..$FFFF to 65C02 RAM memory at $E000..$FFFF.

Good luck on your project, Sir.

Cheerful regards, Mike

Code:
  /*                                                                *
   *  R65C02 Reset Sequence (decoder off), FFFC = ioloc             *
   *                                                                */
     reset_pin = 0;             // reset lo
     cyc_rd(); cyc_rd();        // 2 clocks
     reset_pin = 1;             // reset hi
     cyc_rd();                  // clock 1
     cyc_rd();                  // clock 2
     cyc_rd();                  // clock 3
     cyc_rd();                  // clock 4
     cyc_rd();                  // clock 5
     cyc_wr(io_lo);             // clock 6, Rd FFFC = ioloc lo
     cyc_wr(io_hi);             // clock 7, Rd FFFD = ioloc hi
  /*                                                                *
   *  copy code to RAM (decoder on)                                 *
   *                                                                */
     tblptrl = 0x00;            // point to rom image
     tblptrh = 0xE0;            // at E000..FFFF (8K)
     tblptru = 0x00;            //
     do                         // copy rom image to ram
     { loader(0xA9);            // R DF00 A9, LDA #$nn
       asm tblrd*               //
       loader(tablat);          // R DF01 nn
       loader(0x8D);            // R DF02 8D, STA $hhll
       loader(tblptrl);         // R DF03 ll, aaaa%256
       loader(tblptrh);         // R DF04 hh, aaaa/256
       loader(tblptrh);         // W hhll nn, write op
       loader(0x4C);            // R DF05 4C, JMP ioloc
       loader(io_lo);           // R DF06 00
       loader(io_hi);           // R DF07 DF
       tblptrl++;               // bump pointer
       if(tblptrl == 0)         //
       { tblptrh++;             //
         put232('.');           //
       }                        //
     } while(tblptrh);          // until rollover from 0xFFFF
     crlf();                    //
  /*                                                                *
   *  complete the reset (jmp (fffc)), run 6502 code                *
   *                                                                */
     loader(0x6C);              // R DF00 6C, JMP ($FFFC)
     loader(0xFC);              // R DF01 FC
     loader(0xFF);              // R DF02 FF
     loader(0xFF);              // R DF02 FF (extra cycle)
     loader(0xFF);              // R FFFC ll
     loader(0xFF);              // R FFFD hh


Attachments:
Pocket 65C02 SBC20 (small).png
Pocket 65C02 SBC20 (small).png [ 948 KiB | Viewed 2726 times ]
Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 20, 2015 12:43 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 491
Location: Switzerland
Hi Michael,

thanks for confirming that it works (as can be seen by your project). That's good to know that you already managed to put it into practice. In the meantime I thought about two extensions to my initial design. First I will add a 3-state buffer between the AVR and the data-bus, to avoid conflicts at the falling edge of PHI2 when the AVR is still driving the bus and the 65816 will emit the bank address (the goal is to use it with 65816 of course) and the second change will be that I will connect VP to one of the AVRs input so instead of counting the number of cycles after reset is de-asserted I just wait until VP is asserted (even the number of cycles after a reset is known and fixed) to start sending bytes.

Cheers

Peter


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 20, 2015 2:49 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Hi Peter. Just checking that I've got this right... :)
cbscpe wrote:
When IML is Low addresses $0000 to e.g. $BFFF will select the RAM for read and writes, addresses $C000..$C0FF decode to one of the IO select signals and for addresses $C100..$FFFF selects the RAM only for read accesses. When IML is High the RAM is only selected for write cycles, but not only for $0000..$BFFF but as well for $C100..$FFFF.
So, you have two memory address areas, one that's below the IO in page $C0 and one that's above. When IML is high (active), all writes by the 65xx go to RAM. (And I suppose all reads come from the AVR.) Then, after boot-up, IML will be low. Both the upper and lower RAM areas can be read by the 65xx. The lower area can also be written but writes to the upper area do nothing -- that area is protected. (Nice touch!)

cbscpe wrote:
I will add a 3-state buffer between the AVR and the data-bus, to avoid conflicts at the falling edge of PHI2
'816 does present a bit of a challenge, but IMO the buffer you mention can be avoided. It's to our advantage that the AVR pins that drive the data bus can be switched off (tri-stated or placed in input mode).

Instead of using a 3-state buffer to connect the AVR pins to the 65xx data bus, one alternative is to use eight resistors (about 5k ohms, say) instead. The resistors are smaller, cheaper and they require no control signals. They'll prevent conflicts (bus contention) from causing any harmful effects. (They will also cause delay as each byte from the AVR propagates onto the 65xx data bus. But probably your boot-up loop doesn't require extreme speed anyway.)

Another alternative involves connecting the AVR pins directly to the 65xx data bus. For each byte, the AVR outputs the data then tri-states the pins just before it sets PHI2 low -- and the delay between those two events ought to be kept short. Capacitance on the data bus will cause it to maintain its value for several microseconds at least (and probably hundreds or thousands of microseconds). This is assuming all MOS or CMOS inputs on the bus, and no significant DC leakage from other sources.

cheers,
Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 20, 2015 5:46 pm 
Offline
User avatar

Joined: Wed Feb 13, 2013 1:38 pm
Posts: 589
Location: Michigan, USA
Peter, a couple questions, please?

(1) Does your IML logic in the GAL provide a way to turn off the RAM when your AVR is pushing instructions and operands onto the data bus? This is the only thing I see missing in your description of boot-loader operation. You need to turn off RAM when you push the reset vector bytes and you need to turn off RAM during the 'read' clock cycles in your boot-loader loop.

(2) What's the purpose of the of /RES signal input on the GAL (forgive me, I'm not familiar with GALs)?

BTW, I agree with Jeff that you can probably do without a buffer IC.

Cheerful regards, Mike


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 20, 2015 7:10 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 491
Location: Switzerland
Jeff you got that right. However I will leave the tri-state buffer (74HCT541) because I plan to use the AVR as a PS/2 interface once he did the job of loading the ROM Image. Also I'm not convinced that even a fast AVR can cope with the times required by a W65C816, and the tricks you mention only work in theory and on a perchance base. I don't like that, even so I had sometimes circuits working by magic because of these effects and found out only later when analyzing them after they worked they only work by chance and not by design. As for your question Michael, here is what I first planned to do as a GAL
Code:
GAL22V10
AVRIMLV0


IML   A15   A14   A13   A12   A11   A10   A9    A8    A7    A6    GND
RW    PHI2 /IOA  /IOB  /IOC  /RAM  /BYTE /RD   /WR   /VP    nc    VCC

IOA      =  A15 *  A14 * /A13 * /A12 * /A11 * /A10 * /A9  * /A8  * /A7  * /A6 * /IML

IOB      =  A15 *  A14 * /A13 * /A12 * /A11 * /A10 * /A9  * /A8  * /A7  *  A6 * /IML
      +  A15 *  A14 * /A13 * /A12 * /A11 * /A10 * /A9  * /A8  *  A7  * /A6 * /IML

IOC      =  A15 *  A14 * /A13 * /A12 * /A11 * /A10 * /A9  * /A8  *  A7  *  A6 * /IML


RD      =  RW  *  PHI2

BYTE   =  RW  *  PHI2 * IML

WR      = /RW  *  PHI2

RAM      =  IML * /RW
      + /IML * /A15
      + /IML *  A15 * /A14
      + /IML *  A15 *  A14 * /A13 *  /A12                      *  A8  *  RW
      + /IML *  A15 *  A14 * /A13 *  /A12               *  A9         *  RW
      + /IML *  A15 *  A14 * /A13 *  /A12        *  A10               *  RW     
      + /IML *  A15 *  A14 * /A13 *  /A12 *  A11                      *  RW
      + /IML *  A15 *  A14        *   A12                             *  RW
      + /IML *  A15 *  A14 *  A13                                     *  RW

VP      =  A15 *  A14 *  A13 *  A12 *  A11 *  A10 *  A9  *  A8  *  A7  *  A6

DESCRIPTION



The final details are not done yet, but that's what I'm thinking about. So when IML is active writes and only writes always go to the RAM and reads always go to the byte buffer (/BYTE will connect to /OE of the 74HCT541). IO selects will never be asserted during IML. And you are completely right Michael, in that design /RES does not have to go to the GAL. It's not used in the decoder. Another PIN saved, always handy when starting a design. Thanks for the input.

Again as for the buffer IC, in the AVR code I initially posted I was making use of disabling the outputs (clearing bits in DDRC and DDRD), but the bad thing is that the ATMega328P has no 8-bit port available, so you need to use at least two instructions to disable the PINs on two ports. You may say the ATMega328P has full port B and D but unfortunately PB6&7 are the crystal pins, and I want to use a crystal, and PD0&1 are the USART which I need to be able to download a new ROM image to the flash. I Agree that when using a larger ATMega chip then turning PHI2 off and disabling the outputs in the next cycle using a "out PORTA, zero" should work well. But anyhow, now I will polish the design and code and then build the prototype on a breadboard.

When you think that the equation of IOB is strange, this is on purpose, the 65xx peripherals all have two select pins, one active low that will go to IOB and one active high which will be connected to one of the address lines A4,5,6,7

cheers
Peter


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 20, 2015 8:44 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Quote:
I had sometimes circuits working by magic because of these effects and found out only later when analyzing them after they worked they only work by chance and not by design.
Yes, I've had that happen, too, and I don't like it. It's alarming -- and embarrassing! :D -- that an error escaped my attention. Then the system was able to function anyway thanks to bus capacitance. But, because it wasn't part of the plan, I never calculated the bus-capacitance effect to ensure it would be adequate. That's not a mistake that'll happen when you use the effect deliberately. It can be calculated and it can be adequate -- an engineering option like any other.

The way I would approach this is as a matter of time, resistance and capacitance. The capacitance per bus line depends on the devices connected, and datasheets reveal this figure on a per-chip basis -- you just total 'em up. For the R part of the equation you need to choose a resistance that represents the worst leakage you believe you'll encounter, such as from moisture or contamination on the PCB. [Edit: input leakage on the ICs needs to be considered too.] Then, considering the applicable logic thresholds, you can calculate how long a value can sit on the bus, not being driven by anything, before leakage causes it to become indeterminate.

If 1 Megohm is deemed to be tolerable as the acceptable leakage resistance (to ground or supply), then based on a rough calculation I expect the data bus on your project will hold a value somewhere around 5 microseconds. The AVR can probably switch over in a fraction of that time, so tolerating 1 Megohm is easy -- and that's the worst-case scenario we chose; if there's less leakage the margin increases further. I admit that relying on an arbitrarily-chosen leakage tolerance may seem odd, but I believe it is part of a sound procedure. Comments are welcome, of course. (Oops -- hope you don't mind, Peter. If necessary a new thread can be created.)

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2015 7:05 am 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 491
Location: Switzerland
Ok, I got your point. Now then: the AVR will be clocked with 25MHz (or perhaps even with 30MHz I'll see, how fast the ATMega328P will do at 5.5V), the sequence of "out DDRy, zero" and "out PINx, PHI2", will result in a delay of 40ns respectively 33ns between the outputs going tri-state and PHI2 going low (in my instructions example PHI2 will contain the bit mask that corresponds to the PIN used on Port x for PHI2, modern AVR toggle the output when writing a 1 to the PIN register, this is the fastest 1-cycle trick to change a single bit on a port, and zero of course is the name of the register that has my constant 0x00). So when disabling the output first and then driving PHI2 low we need to have enough capacitance to drive the data-pins via the RC construct. R should be not to low to avoid excess power consumption during operation, I would say 10kohm should do it and when using all CMOS ports this will drive the pins easily to full VCC or GND. So for an acceptable in/decrease of 1V and a delay of 40ns I would need approx 22pF connected to the AVR pins. So your Idea seems feasible and the capacitance load for the AVR pins is not beyond the specs.

With this I have saved a 74HCT541, but on the other hand I need 8 resistors and 8 capacitors. Not a good trade-in for a digital circuit I would say.

But, I have another idea, why not use a D-Flip-Flop (74AC74) and delay the change of PHI2 by one AVR Clock-Cycle? So I first change PHI2 and then disable the output. The ATMega328P can be configured to have a full-swing XCO output which can be used as clock input to the FF and the PHI2 output of the AVR will connect to the D-Input of the FF. Then the falling edge and the disabling of the AVR outputs, as seen by the W65C816, happens at the same time.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2015 3:20 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
cbscpe wrote:
the sequence of "out DDRy, zero" and "out PINx, PHI2", will result in a delay of 40ns respectively 33ns between the outputs going tri-state and PHI2 going low [...]
OK, that's excellent.

Quote:
With this I have saved a 74HCT541, but on the other hand I need 8 resistors and 8 capacitors
Sorry for the confusion. At first I proposed two solutions, one of which involved adding resistors. In the subsequent post I abandoned that because it's better with no resistors. Neither solution involves adding capacitors, because there's enough capacitance already. I haven't checked the figures, but the CPU, the AVR and the RAM contribute roughly 5 pF each, so we have about 15 pF working in our favor. With this solution the AVR pins attach directly to the 65xx data bus.

At the instant of the "out DDRy, zero" we know all the 8 data lines will be valid -- either high or low. IOW on each line, the 15 pF will be either charged to Vcc or discharged to 0. After the "out DDRy, zero," each line will tend to REMAIN charged or discharged. They remain until something eventually disturbs them, and the "something" is the leakage resistance i mentioned. Minimal leakage means minimal disturbance.

In the theoretical case of zero leakage a capacitor will remain charged for all of eternity. But we only need it to remain for 40 ns. :)

Quote:
I have another idea, why not use a D-Flip-Flop (74AC74) and delay the change of PHI2 by one AVR Clock-Cycle? [...] Then the falling edge and the disabling of the AVR outputs, as seen by the W65C816, happens at the same time.
It's a clever idea, and it does reducing the duration of the "floating" period from 40 ns to approximately zero. But is that a benefit? What it translates to is better ability to tolerate leakage due to contamination on the board -- and that's already adequately satisfied, I would say. The situation would be different if you had some TTL loads on the bus, because they don't have super-high input impedance like that on MOS and CMOS devices.

BTW you need to check that the AVR really does present a high impedance when its outputs are switched off. IOW make sure they haven't "helpfully" included a pullup resistor internally on each port pin. We don't want that, although for some applications it's an advantage.

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2015 7:34 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 491
Location: Switzerland
Hi Jeff,

ok now I get a clearer picture of what you meant. As for the AVR pins, when set as input (DDRD.n=0) they have a very high impedance. I already have started the prototype

Attachment:
File comment: Almost finished breadboard layout
IMG_0320.JPG
IMG_0320.JPG [ 3.26 MiB | Viewed 2600 times ]


What is missing are the various pull-ups (IRQ, RES, NMI ...) and a final check and then I will power it up.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 23, 2015 7:34 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 491
Location: Switzerland
Hi,

here is an update to the project. First I have implemented a first version of the hardware. Here es the schematic. There is one difference, I use a W65C816 and not a R65C02 as in the schematic, the problem is I did not update my library to have a W65C816, but I think it is obvious what is different.

Attachment:
File comment: Currently implemented HW on breadboard
bootstrap-design.pdf [27.36 KiB]
Downloaded 98 times

Outputs controlled by the AVR are PHI2, RES and IML. The AVR also can read the status of VPA, VDA, VPB and RW. I have written a small interactive test program for the AVR so I can step through 6502 cycles. The test program is a "rewrite" of the logic of the Apple II monitor, so the syntax is the same. The following commands for the 6502 cycleing are implemented
Code:
1R   Assert Reset (Pull it Low)
0R   De-assert Reset (Pull it high, respectively turn the output pin to input and let the pull-up resistor do its work
P     Toggle PHI2
I      Toggle IML
nnW Execute a cycle where nn is the byte to put onto the databus
S      Show status of VPA, VDA, VPB and RW


I have attached the source code
Attachment:
File comment: AVR Source Code
AVRIML.asm [16.68 KiB]
Downloaded 83 times


So a typical sequence to init the 6502 would use the following commands, I have shown here a session with each step and instruction entered as a line

Code:
*1rwwwww0r

*wswswswswsws
VPA:0, VDA:0,VPB:1,R/W:1
VPA:1, VDA:1,VPB:1,R/W:1
VPA:0, VDA:0,VPB:1,R/W:1
VPA:0, VDA:1,VPB:1,R/W:1
VPA:0, VDA:1,VPB:1,R/W:1
VPA:0, VDA:1,VPB:1,R/W:1

*1rwwwww0r

*wswswswswswsws
VPA:0, VDA:0,VPB:1,R/W:0
VPA:1, VDA:1,VPB:1,R/W:1
VPA:0, VDA:0,VPB:1,R/W:1
VPA:0, VDA:1,VPB:1,R/W:1
VPA:0, VDA:1,VPB:1,R/W:1
VPA:0, VDA:1,VPB:1,R/W:1
VPA:0, VDA:1,VPB:0,R/W:1

*0ws3ws
VPA:0, VDA:1,VPB:0,R/W:1
VPA:1, VDA:1,VPB:1,R/W:1

*a9ws00ws
VPA:1, VDA:0,VPB:1,R/W:1
VPA:1, VDA:1,VPB:1,R/W:1

*8dwsaawsaaws00ws
VPA:1, VDA:0,VPB:1,R/W:1
VPA:1, VDA:0,VPB:1,R/W:1
VPA:0, VDA:1,VPB:1,R/W:0
VPA:1, VDA:1,VPB:1,R/W:1

*4cws00ws03ws
VPA:1, VDA:0,VPB:1,R/W:1
VPA:1, VDA:0,VPB:1,R/W:1
VPA:1, VDA:1,VPB:1,R/W:1

*


Note that the S(tatus) command displays the status of the signals after the cycle as endend. That is PHI2 is normally LOW and W first places the byte to the buffer and then creates a short positive pulse on PHI2 for approx 300ns.

As you can see VPB is pulled low also for fetching the reset vector. So that means after a reset I can just emit PHI2 cycles until VPB is LOW and then I know the 6502 wants to read the reset vector and then start the Initial Machine Load as was the reason for the project.

Cheers

Peter


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 24, 2015 1:29 am 
Offline
User avatar

Joined: Wed Feb 13, 2013 1:38 pm
Posts: 589
Location: Michigan, USA
Hi Peter,

Why is R/W low during the first cycle after the second reset?


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 24, 2015 3:57 am 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 491
Location: Switzerland
Good question, I don't know and I was also surprised. It happens from time to time. It appaers also that it is 6 cycles before the 65816 reads the vector and not 5 as I thought, although I think I've seen also a discussion where they count 6. Perhaps it is because I deassert reset when PHI2 is low. It could also be a flaw in my software of the AVR. I will investigate that and also another problem I have observed sporadically. But first I will to add code that loads a simple HELLO WORLD program, I also have a ACIA on my breadboard.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 24, 2015 9:11 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10980
Location: England
If you see something which sometimes happens and sometimes doesn't, I think probably you are not holding reset for long enough.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 28 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 19 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: