6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Apr 27, 2024 7:49 pm

All times are UTC




Post new topic Reply to topic  [ 564 posts ]  Go to page Previous  1 ... 34, 35, 36, 37, 38
Author Message
PostPosted: Mon Nov 06, 2023 2:37 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
kernelthread wrote:
Dr Jefyll wrote:
The complication is that Phi2 is usually what's used to qualify the /WE pulse that's sent to RAM and to non-65xx peripherals. And that's fine for devices that don't need extra time, because you want the rise of Phi2 to cause /WE to go low without delay. But in the case of a device that does need extra time, there could be trouble ("rogue" writes to incorrect addresses) if Phi2 causes /WE to go low without delay.

This seems to imply that by the time Phi2 rises we need to know whether or not extra time will be required. And, in an overclocked system, knowing this by the time Phi2 rises is a problem. :(

Okay, so this morning I'm doing a head slap. :oops: The problem goes away if devices that need extra time don't use the same /WE pulse that's sent to fast devices. A little extra logic can give slow devices a /WE pulse of their own -- it would be a fairly minor addition to the clock-stretch circuit. Forgive me if that's what you already had in mind, kernelthread.

-- Jeff


To be honest, I hadn't realised this might be a problem. I was just considering a system consisting of RAM, ROM and VIA(s). RAM WE can be qualified with PHI2 as usual, as can WE for Flash memory if that is being used for ROM. VIAs are a problem because the chip select has to be asserted before the VIA input clock rises. But then you also don't really want to use PHI2 as the VIA input clock because the timers will be affected by clock stretching - you ideally want a constant clock input to the VIA so you can get predictable timing intervals.

I've come up with some Verilog code (not tested) to do what I was thinking of:

Code:

input FCLK;         // fast clock, 2 x nominal CPU frequency
input nRST;         // system reset signal

reg [2:0] STATE;   // Clock stretch state (see below)
reg PHI2;         // clock to CPU
reg VIA_CLK;      // clock for VIAs and similar peripherals (half nominal CPU frequency, constant frequency)
reg VIA_SEL;      // chip select for VIAs
                    // asserted when VIA_CLK is low when VIA access is needed
                    // deasserted at following VIA_CLK falling edge
reg DELAYED_SEL;    // delayed chip select for any other purpose
                    // asserted at beginning of first stretch cycle
                    // deasserted at end of bus cycle
                    // maybe useful if any device requires more settling time before RD/WR strobes activated

/* STATE values:

000     First half cycle of every bus cycle, PHI2 = 0
001     Second half cycle of every bus cycle, PHI2 = 1. Last half cycle if no stretching needed.
010     6 input clocks (3 nominal CPU cycles) remaining, PHI2 = 1
011     5 input clocks (2.5 nominal CPU cycles) remaining, PHI2 = 1
100     4 input clocks (2 nominal CPU cycles) remaining, PHI2 = 1
101     3 input clocks (1.5 nominal CPU cycles) remaining, PHI2 = 1
110     2 input clocks (1 nominal CPU cycles remaining, PHI2 = 1
111     Last half cycle following stretch, PHI2 = 1

*/

// These logic terms should be capable of evaluation within one clock period of FCLK
// It is assumed they are functions of the active address, so remain asserted for the entire bus cycle
wire STRETCH1 = ... ;   // insert logic to determine if device needs stretch by 1 cycle
wire STRETCH2 = ... ;   // insert logic to determine if device needs stretch by 2 cycles
wire STRETCH3 = ... ;   // insert logic to determine if device needs stretch by 3 cycles
wire IS_VIA = ... ;      // insert logic to determine if it's a VIA

always @(posedge FCLK or negedge nRST) begin
   if (!nRST) begin
      STATE <= 3'b000;
      PHI2 <= 1'b0;
      VIA_CLK <= 1'b0;
      VIA_SEL <= 1'b0;
      DELAYED_SEL <= 1'b0;
   end
   else if (STATE == 3'b000) begin
        // CPU clock is low in state 000, high in any other state
      STATE <= 3'b001;
      PHI2 <= 1'b1;
   end
    else if (STATE == 3'b001) begin
        // Second state of bus cycle - need to determine required wait states
        // by the end of this state.
        if (STRETCH1) begin
            // state increments twice before PHI2 goes low again
            STATE <= 3'b110;

            // delayed select asserted at beginning of stretch
          DELAYED_SEL <= 1'b1;
        end
        else if (STRETCH2) begin
            // state increments 4 times before PHI2 goes low again
            STATE <= 3'b100;

            // delayed select asserted at beginning of stretch
          DELAYED_SEL <= 1'b1;
        end
        else if (STRETCH3) begin
            // state increments 6 times before PHI2 goes low again
            STATE <= 3'b010;

            // delayed select asserted at beginning of stretch
          DELAYED_SEL <= 1'b1;
        end
        else if (IS_VIA) begin
            // VIA_CLK will toggle at the next input clock, however it is not
            // known whether it will go low or high
            // If it will go low, assert VIA_SEL at the same time and do a 2 cycle stretch
            // If it will go high, don't assert VIA_SEL yet, but start a 3 cycle stretch
            // VIA_SEL will be asserted after 1 cycle of stretch
            if (VIA_CLK) begin
                // VIA_CLK will go low at next input clock, so assert VIA_SEL there as well
                VIA_SEL <= 1'b1;

                // need 2 cycle stretch
                STATE <= 3'b100;
            end
            else begin
                // need 3 cycle stretch, don't assert VIA_SEL yet
                STATE <= 3'b010;
            end
        end
        else begin
            // no stretching needed - back to PHI2=0
            STATE <= 3'b000;
          PHI2 <= 1'b0;
        end
    end
    else if (STATE == 3'b111) begin
        // Last state of bus cycle following stretching
        // Back to PHI2=0 on next input clock
        STATE <= 3'b000;
      PHI2 <= 1'b0;

        // VIA select deasserted here
        VIA_SEL <= 1'b0;

        // delayed select deasserted here
      DELAYED_SEL <= 1'b0;
    end
    else begin
        // stretching operation underway but not yet at the end
        // states 010, 011, 100, 101, 110
        if ((STATE == 3'b011) & IS_VIA) begin
            // VIA_CLK will go low at next input clock, so assert VIA_SEL there as well
            VIA_SEL <= 1'b1;
        end

        STATE <= STATE + 3'b001;
    end

    if (STATE[0]) begin
        // VIA_CLK toggles whenever unstretched clock would fall
        // i.e. when state number transitions from odd to even
        VIA_CLK <= ~VIA_CLK;
    end
end


I added a DELAYED_SEL signal to accommodate any devices which need additional settling time for the address and/or data before being activated, following your suggestion.


First, I am sot sure if this makes a difference to a CPLD but in an FPGA it may.

This is a bit of nit-picking on Verilog code, but using case statements instead of if/else if logic may generate faster code that uses fewer resources.
If/else if statements generate a priority encoder which may be cascaded logic, while case statements use decoders which often have support built into the PLD.

Altered (untested) code shown below.

Code:
always @(posedge FCLK or negedge nRST) begin
   if (!nRST) begin
      STATE <= 3'b000;
      PHI2 <= 1'b0;
      VIA_CLK <= 1'b0;
      VIA_SEL <= 1'b0;
      DELAYED_SEL <= 1'b0;
   end
   else begin
      // We always want the next state unless overridden.
    STATE <= STATE + 3'b001;

      case(STATE)
      3'b000:
         begin
        // CPU clock is low in state 000, high in any other state
        //STATE <= 3'b001;
         PHI2 <= 1'b1;
         end
      3'b001:
       begin
          casez({STRETCH1,STRETCH2,STRETCH3,IS_VIA})
        // Second state of bus cycle - need to determine required wait states
        // by the end of this state.
        4'b1???:
           begin
            // state increments twice before PHI2 goes low again
            STATE <= 3'b110;

            // delayed select asserted at beginning of stretch
             DELAYED_SEL <= 1'b1;
           end
        4'b01??:
           begin
            // state increments 4 times before PHI2 goes low again
            STATE <= 3'b100;

            // delayed select asserted at beginning of stretch
             DELAYED_SEL <= 1'b1;
           end
        4'b001?:
           begin
            // state increments 6 times before PHI2 goes low again
//            STATE <= 3'b010;

            // delayed select asserted at beginning of stretch
             DELAYED_SEL <= 1'b1;
          end
        4'b0001:
            // VIA_CLK will toggle at the next input clock, however it is not
            // known whether it will go low or high
            // If it will go low, assert VIA_SEL at the same time and do a 2 cycle stretch
            // If it will go high, don't assert VIA_SEL yet, but start a 3 cycle stretch
            // VIA_SEL will be asserted after 1 cycle of stretch
            if (VIA_CLK) begin
                // VIA_CLK will go low at next input clock, so assert VIA_SEL there as well
                VIA_SEL <= 1'b1;

                // need 2 cycle stretch
                STATE <= 3'b100;
            end
            else begin
                // need 3 cycle stretch, don't assert VIA_SEL yet
//                STATE <= 3'b010;
            end
        default:
           begin
            // no stretching needed - back to PHI2=0
            STATE <= 3'b000;
             PHI2 <= 1'b0;
          end
        endcase
       end
    3'b111:
       begin
        // Last state of bus cycle following stretching
        // Back to PHI2=0 on next input clock
//        STATE <= 3'b000;
         PHI2 <= 1'b0;

        // VIA select deasserted here
        VIA_SEL <= 1'b0;

        // delayed select deasserted here
         DELAYED_SEL <= 1'b0;
       end
    3'b011:
       begin
        // stretching operation underway but not yet at the end
        // states 010, 011, 100, 101, 110
        if (IS_VIA) begin
            // VIA_CLK will go low at next input clock, so assert VIA_SEL there as well
            VIA_SEL <= 1'b1;
        end
    default:   ;
    endcase

    end

    if (STATE[0]) begin
        // VIA_CLK toggles whenever unstretched clock would fall
        // i.e. when state number transitions from odd to even
        VIA_CLK <= ~VIA_CLK;
    end
end

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 09, 2024 9:22 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8144
Location: Midwestern USA
POC V1.3 has achieved 110 days of uptime, as I monkey around with a new-fangled S-record loader that will include some features I originally omitted, e.g., being able to process S2 and S8 records.  Those normally wouldn't be used with a 65C02, but are useful with the 65C816, since a program can be assembled to run in extended RAM.

Just for reference, attached is the assembly listing for V1.3’s firmware.  Someone might find something useful in it.

Attachment:
File comment: POC V1.3’s Firmware, V2.7.0
firmware_2_7_0.txt [682.81 KiB]
Downloaded 55 times

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 10, 2024 7:12 am 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 745
Location: Germany
Personally I really like the PGZ format for loading programs over serial as its very easy to write a loader for compared to a lot of other formats (atleast for me).

When I setup the gcc toolchain for my 68000 SBC a month ago or so it obviously didn't have PGZ as an output option. But i didn't want to write an SREC loader in 68k assembly, so i did the only logical thing: I learned the ELF file format, and wrote a desktop program to convert an ELF executable into a PGZ file. :D


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 10, 2024 8:17 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8144
Location: Midwestern USA
Proxy wrote:
Personally I really like the PGZ format for loading programs over serial as its very easy to write a loader for compared to a lot of other formats (atleast for me).

After reading about PGZ (and PGX), I’m unimpressed.  Neither has any apparent error-detection provisions, and both appear to be one-off formats.  The S-record format has record checksumming, plus additional mechanisms for error detection, and is a de facto standard.  Also, like Intel hex and other similar formats, S-record is pure ASCII, making it suitable for transmission through a medium that wouldn’t gracefully handle binary data.  I’m not seeing any compelling reason to monkey with PGZ.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 10, 2024 8:23 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10793
Location: England
Elsewhere, BDD, I'm pretty sure you've said short-range serial connections are reliable. So we shouldn't expect any corruption on the wire. Having said that, small systems like ours might often initially have problems with flow control or overrun, so a final checksum might be a good idea.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 10, 2024 10:19 am 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 745
Location: Germany
I've never really had a need or saw a reason for exact line by line error checking in a hobbyist environment where wire runs are only a few meters at most and any data corruption can be solved by just resetting the system and/or resending the file.
And I actually like that it's not ASCII, makes the file size smaller and loading a bit faster as you don't need any kind of conversion. And what do you mean with serial not handling raw binary well? I've never hd any issues with that.

Though I guess a complete checksum at the end (or start) of the file would be a good addition, I have created a slightly modified version of PGZ called PGW which adds an endianess option, so I could just add a 32-bit checksum in the header and make that part of the format.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 10, 2024 10:24 am 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1399
Location: Scotland
Sorry - can't resist adding this at this point: https://xkcd.com/927/

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 10, 2024 11:00 am 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 745
Location: Germany
Ah good old XKCD.
But the thing is I dont really see these as "competing" standards, just as options. So anyone can choose whatever format fits their requirements and use case.
For example, I don't need error checking and just wanted something easy to parse and fast, so PGZ turned out to be the best option for me. I didn't mean to imply that it's perfect for every case.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 10, 2024 7:51 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8144
Location: Midwestern USA
BigEd wrote:
Elsewhere, BDD, I'm pretty sure you've said short-range serial connections are reliable.  So we shouldn't expect any corruption on the wire.

That is true, assuming the hardware driving the link is properly performing.  I know from past experience that high-quality hardware can reliably drive a TIA-232 link at 115.2Kbps over 50 meters, assuming the use of CAT5 UTP and the link being kept away from sources of strong, fluctuating magnetism (e.g., large AC motors), EMI and ESI.  At the distances we use in our hobby, I’d expect very little signal degradation.

Quote:
Having said that, small systems like ours might often initially have problems with flow control or overrun, so a final checksum might be a good idea.

Agreed.  Overrun is always a risk, especially if using the 65C51 or similar.  I can deliberately induce overrun in my POC units during data transfer from my development server, despite the 28L92’s 16-deep FIFOs.  All that is needed is a slow Ø2 clock.  :D

Without at least a basic checksum process, how would it be known if a datum got clobbered?

Proxy wrote:
I've never really had a need or saw a reason for exact line by line error checking in a hobbyist environment where wire runs are only a few meters at most and any data corruption can be solved by just resetting the system and/or resending the file.

As said above, the length of a TIA-232 link in a hobby environment is seldom a factor in reliable transmission.  Problems with the receiving station are more likely to result in errors, as Ed notes.  I personally would find it really annoying to have to start all over just because of a one-byte error.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 564 posts ]  Go to page Previous  1 ... 34, 35, 36, 37, 38

All times are UTC


Who is online

Users browsing this forum: No registered users and 31 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: