SHIFTER reimplementation on FPGA

GFA, ASM, STOS, ...

Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

SHIFTER reimplementation on FPGA

Postby Smonson » Thu Dec 07, 2017 1:12 am

Thanks again Ijor :cheers:. My verilog implementation isn't able to run {Closure} properly still, so I'm trying to work out what is different from the real IC. That explanation is excellent, I should have re-read the whole thread before posting.

I think I have everything working exactly like your diagram now (apart from the initial pixel counter which the mux initialises to 3 instead of 4 to avoid the every-16-pixels issue when the machine is cold). But there's clearly either a bug that I've overlooked, or something else that needs to be in there which I haven't seen any documentation for yet. That's why I asked about pixCtrLoad.

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: ST Chipset decap

Postby ijor » Thu Dec 07, 2017 1:43 am

Smonson wrote:My verilog implementation isn't able to run {Closure} properly still, so I'm trying to work out what is different from the real IC.


I thought you were taking the digital outputs from Shifter, but I guess you want to replace Shifter altogether, that's nice :)

Well, I can't say why your implementation is failing, not without more details. But there are quite some async issues on Shifter that might be difficult to reproduce on modern hardware.

How are you implementing the clock mux that makes the pixel clock on the different resolutions?

(apart from the initial pixel counter which the mux initialises to 3 instead of 4 to avoid the every-16-pixels issue when the machine is cold)


I'm not completely sure you can do that without some collateral consequences.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: ST Chipset decap

Postby Smonson » Thu Dec 07, 2017 3:15 am

ijor wrote:I thought you were taking the digital outputs from Shifter, but I guess you want to replace Shifter altogether, that's nice :)

Right now I'm replacing the shifter, because I need the 32MHz shifter clock, and at the time when I started this I didn't realise that most shifters are soldered in place. But I'm pretty sure it will work the same either way. But plugging into the shifter socket is a much easier and non-destructive way to install the mod.

But there are quite some async issues on Shifter that might be difficult to reproduce on modern hardware. How are you implementing the clock mux that makes the pixel clock on the different resolutions?

Originally my implementation was much simpler than the real shifter. It just sycnhronises scanlines to DE, and loads RR from IR every 4th LOAD. That is a rock-solid implementation that uses not too many gates. It works for the main ST video modes, and doesn't need VSYNC, so it can work straight from the shifter socket with a short ribbon cable. But then overscan tricks come into it, which have turned out to be the far harder problem to solve for a person without intimate knowledge of how they work.

The pixel clocks just come from a divider to create the 16 and 8MHz clocks from the 32MHz system clock.

I'm not completely sure you can do that without some collateral consequences.

You may be right. Actually I have solved a couple of bugs since I made that decision, so I might change it back now and see if the problem returns.

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: ST Chipset decap

Postby ijor » Thu Dec 07, 2017 4:06 am

Smonson wrote:It just sycnhronises scanlines to DE, and loads RR from IR every 4th LOAD.


Depending the exact meaning of the above sentence, I'm not sure that's the best way. It might be better to synchronize to the first LOAD pulse as the real Shifter does. If you follow DE you might get into some wakeup issues. Remember the relation between DE and LOAD depends on the wakeup.

The pixel clocks just come from a divider to create the 16 and 8MHz clocks from the 32MHz system clock.


Yes, that is pretty obvious. But how you switch and mux between the three clocks?

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: ST Chipset decap

Postby Smonson » Thu Dec 07, 2017 4:31 am

ijor wrote:
Smonson wrote:It just sycnhronises scanlines to DE, and loads RR from IR every 4th LOAD.

Depending the exact meaning of the above sentence, I'm not sure that's the best way. It might be better to synchronize to the first LOAD pulse as the real Shifter does. If you follow DE you might get into some wakeup issues. Remember the relation between DE and LOAD depends on the wakeup.

I forgot to mention it but I also clear all the registers at the start of each DE, so each line begins fresh on the first LOAD after DE. DE isn't used for anything else apart from that, so as long as all LOADs fall within the DE period, it's bullet-proof.

Yes, that is pretty obvious. But how you switch and mux between the three clocks?

Something like this:

Code: Select all

wire pixel_clock = resolution == 2 ? CLOCK_32 : (resolution == 1 ? CLOCK_16 : CLOCK_8);

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: ST Chipset decap

Postby ijor » Thu Dec 07, 2017 12:03 pm

Smonson wrote:I forgot to mention it but I also clear all the registers at the start of each DE, so each line begins fresh on the first LOAD after DE.


That's still how you do it? Or that was only on the original, simple, implementation? Because resetting the line logic unconditionally like that will break Closure.

Code: Select all

wire pixel_clock = resolution == 2 ? CLOCK_32 : (resolution == 1 ? CLOCK_16 : CLOCK_8);


This kind of mux might glitch when the resolution is changed. It also creates clock skew. You must be very careful for the transfers between the muxed and the original system clock.

User avatar
alexh
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2679
Joined: Wed Oct 20, 2004 1:52 pm
Location: UK - Oxford
Contact:

Re: ST Chipset decap

Postby alexh » Thu Dec 07, 2017 1:08 pm

ijor wrote:
Smonson wrote:

Code: Select all

wire pixel_clock = resolution == 2 ? CLOCK_32 : (resolution == 1 ? CLOCK_16 : CLOCK_8);

This kind of mux might glitch when the resolution is changed. It also creates clock skew. You must be very careful for the transfers between the muxed and the original system clock.

FPGA's really don't like this type of clock multiplexor.

I would recommend that if you HAVE to use a clock mux then use a macro so you can replace the underlying logic with a primitive which is technology dependant.

e.g. For Xilinx you could use a BUFGMUX_CTRL perhaps

I try to design everything I can to work on a single fast clock and use clock-enables to run logic at lower speeds (Not always possible)

Some FPGA tools will allow you to infer clock enables by specifying two clocks with a constraint which defines a relationship between the two. That way you do not have to go back and re-write RTL which doesn't have a clock enable input explicitly defined.

Writing the RTL is only one part of the problem. Writing good constraints is the other.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: ST Chipset decap

Postby Smonson » Thu Dec 07, 2017 11:25 pm

ijor wrote:
Smonson wrote:I forgot to mention it but I also clear all the registers at the start of each DE, so each line begins fresh on the first LOAD after DE.


That's still how you do it? Or that was only on the original, simple, implementation? Because resetting the line logic unconditionally like that will break Closure.


That's for the simple implementation only. For the "accurate" implementation, I have removed anything that doesn't appear in your diagrams.

This kind of mux might glitch when the resolution is changed. It also creates clock skew. You must be very careful for the transfers between the muxed and the original system clock.

That's interesting, I didn't know that. Thanks for the info. I don't think skew would be much of a problem - it would have to reach quite a big delay to affect anything, but glitches could be potentially, although I haven't seen any clock issues yet. I guess I can implement it using sequential logic instead, I'm still new to the world of FPGAs.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: ST Chipset decap

Postby Smonson » Thu Dec 07, 2017 11:45 pm

alexh wrote:FPGA's really don't like this type of clock multiplexor.

I would recommend that if you HAVE to use a clock mux then use a macro so you can replace the underlying logic with a primitive which is technology dependant.

e.g. For Xilinx you could use a BUFGMUX_CTRL perhaps


I'm using a Cyclone-II. Thanks for the advice. Using a divided clock is really not necessary anyway - I have had everything derived from the 32MHz master clock before, and from what you've both said I'll switch back to that implementation again.

I don't think the clock is causing any problem, lack of information about how the shifter works is what's stopping this from progressing right now. I think I'm going to forget about it for now and stick to the standard video modes until I can find out from a programmer how the overscan techniques are supposed to work.

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: ST Chipset decap

Postby ijor » Fri Dec 08, 2017 3:12 am

Smonson wrote:I don't think skew would be much of a problem - it would have to reach quite a big delay to affect anything, ...


No, the problem with clock skew is usually not setup timing, but hold timing. A minimum clock skew might be enough to create hold timing violations.

I have had everything derived from the 32MHz master clock before, and from what you've both said I'll switch back to that implementation again.


I agree, that's the best way, yes.

I don't think the clock is causing any problem, lack of information about how the shifter works is what's stopping this from progressing right now. I think I'm going to forget about it for now and stick to the standard video modes until I can find out from a programmer how the overscan techniques are supposed to work.


What information exactly are you missing? Note that Closure is a very special case. You don't need to do anything special to support overscan. Overscan is mostly a GLUE thing. Did you try other overscan software? Most overscan software should work with a Shifter simple implementation.

For the few cases that need more precise Shifter "emulation", it depends a lot on the clock mux, believe it or not. :)

One more thing. If you connect only to the Shifter socket you will miss the Blank signal. It's not too critical, but a few demos do use it to hide some garbage, and without the signal you will display pixels that are supposed to be blanked.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: ST Chipset decap

Postby Smonson » Fri Dec 08, 2017 4:17 am

ijor wrote:What information exactly are you missing? Note that Closure is a very special case. You don't need to do anything special to support overscan. Overscan is mostly a GLUE thing. Did you try other overscan software? Most overscan software should work with a Shifter simple implementation.


No way to know what information is missing... Right now, overscan is working, but doesn't show correct results for Closure and other demos, so there's something missing from my model. For example, in the first screen of Closure, the small SYNC logo (which is displayed using overscan even though it doesn't reach the screen edges) works fine except that all the colours are wrong, so possibly the bitplanes are out of order.

So there are two parts to this - there is the shifter model, and there's the software techniques that perform certain actions at certain times in order to get an expected result. It would be easier to know where the shifter model differs from the real shifter if I had the knowledge of how the overscan techniques work so I could see where the expected result doesn't appear.

One more thing. If you connect only to the Shifter socket you will miss the Blank signal. It's not too critical, but a few demos do use it to hide some garbage, and without the signal you will display pixels that are supposed to be blanked.


That's a feature that it would be good to have. If I'm hooking up VSYNC anyway, then I can also add Blank as well, since it directly affects the video output with no fancy business it would literally take five minutes to implement.

User avatar
troed
Atari God
Atari God
Posts: 1398
Joined: Mon Apr 30, 2012 6:20 pm
Location: Sweden

Re: ST Chipset decap

Postby troed » Fri Dec 08, 2017 9:11 am

Smonson wrote:For example, in the first screen of Closure, the small SYNC logo (which is displayed using overscan even though it doesn't reach the screen edges) works fine except that all the colours are wrong, so possibly the bitplanes are out of order.


I'm happy to explain everything in detail :) The following is slightly simplified, but a good starting point.

{Closure} is a special case. It sits somewhere in between "regular" fullscreens and the "4-bit sync scrollers". A regular fullscreen is done with GLUE tricks only and the Shifter can sort of be ignored (and should work with a simple model).

A 4-bit sync scroller is done through both fullscreen (GLUE) techniques but also making use of the fact that you can desync the Shifter so that it leaves some words in the internal registers between lines.

{Closure} doesn't use 4-bit sync scrolling techniques, but it does make use of the words left in registers capability to (mostly) succeed in avoiding having to "clear" the Shifter at the end of each line. Thus, you need to emulate the internal registers and when to clear and not clear them for {Closure} to display correctly.

So, yes. The first small logo dist will indeed be one bitplane off otherwise.

Additionally, {Closure} detects which wakestate the machine boots in and adjusts all code accordingly. This means that you should probably run a wakestate detection routine whenever you test yourself, to make sure you don't see "random" effects which in reality are caused by the different wakestates. I suggest (of course) using the boot sector I made specifically for this as the fastest possible test ;)

Although, I would agree that you should probably get "all" regular fullscreens working correctly before attacking the Shifter specific code in {Closure} and 4-bit sync scrollers ...

https://github.com/troed/WSDETECT

/Troed

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: ST Chipset decap

Postby ijor » Sat Dec 09, 2017 5:04 am

I added schematics for the original clock generator here: viewtopic.php?f=16&t=29658&p=333893#p333893

Note that it uses a simple combinatorial mux, exactly what we recommended not to do. But an old school ASIC is completely different than a modern FPGA. And this is precisely one of the challenges here. To emulate precisely and exactly the asynchronous behavior of circuits like this.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: SHIFTER reimplementation on FPGA

Postby Smonson » Sat Dec 09, 2017 8:03 am

Thanks for the extra info Troed. As far as I can tell the register behavior clearing/not clearing should be working. I think the problem is when you're doing register writes mid-scanline, it's triggering reset because LOAD and CS are asserted together. I don't think this is really happening but the signal on the FPGA (combinatorial) is getting triggered. I need to look into it but don't have time this weekend. I'll come back to the problem soon ☺

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: SHIFTER reimplementation on FPGA

Postby ijor » Sat Dec 09, 2017 3:46 pm

Smonson wrote:I think the problem is when you're doing register writes mid-scanline, it's triggering reset because LOAD and CS are asserted together. I don't think this is really happening but the signal on the FPGA (combinatorial) is getting triggered.


I would suspect that the problem is something else. Does Spectrum 512 work? Spectrum 512 writes constantly during the whole line.

Conceivably there is a synchronization issue with LOAD and CS. I would delay triggering reset after confirming it's stable for a couple of cycles.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: SHIFTER reimplementation on FPGA

Postby Smonson » Sun Dec 10, 2017 1:22 am

I don't know, I'll see if I can find a copy online

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: SHIFTER reimplementation on FPGA

Postby ijor » Sun Dec 10, 2017 1:53 am

Ah. You should test it first. It is more important to run Spectrum 512 than the couple of demos that need an advanced Shifter model. Spectrum changes the palette on the fly. You might need to fine tune your timing.

It is here: http://www.atarimania.com/utility-atari ... 22312.html

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: SHIFTER reimplementation on FPGA

Postby Smonson » Tue Jun 26, 2018 2:54 pm

This is fairly stable now, so I'm sharing the verilog model that I'm using.
Spectrum 512 works as long as the pixel count initial value is changed from 4 to 2.

Code: Select all

// Shifter model based on Ijor's reverse-engineering.

`define RISING 2'b01
`define FALLING 2'b10
`define HIGH 2'b11
`define LOW 2'b00

module shifter(CLOCK_32, de, cs, load, data, data_out, rw, addr, oe, r, g, b);
   input CLOCK_32;
   input de, cs, load, rw;
   input [15:0] data;
   output [15:0] data_out;
   input [4:0] addr;
   output oe;
      
   // STE-style palettes with LSB in position 3
   output [3:0] r = resolution == 2 ? (mono ? 4'b1111 : 4'b0000) :
      {palette[palette_index][10:8], palette[palette_index][11]};
   output [3:0] g = resolution == 2 ? (mono ? 4'b1111 : 4'b0000) :
      {palette[palette_index][6:4], palette[palette_index][7]};
   output [3:0] b = resolution == 2 ? (mono ? 4'b1111 : 4'b0000) :
      {palette[palette_index][2:0], palette[palette_index][3]};
   // FIXME: was mono's palette derived from colour zero's low bit or something?
   // gotta look that up.

   reg [15:0] shift_rr[3:0];
   reg [15:0] shift_ir[3:0];
   reg [15:0] resolution_register;
   wire [1:0] resolution = resolution_register[1:0];
   reg [11:0] palette [15:0];
   
   wire [3:0] palette_low = {
      shift_rr[3][15],
      shift_rr[2][15],
      shift_rr[1][15],
      shift_rr[0][15]
   };

   wire [1:0] palette_med = {
      shift_rr[1][15],
      shift_rr[0][15]
   };
   
   wire mono = shift_rr[0][15];
   
   wire [3:0] palette_index = resolution == 0 ? palette_low : {2'b00, palette_med};
   wire reset = load_state == `RISING && !cs;
   
   reg [1:0] de_state;
   reg [1:0] load_state;
   reg [3:0] load_count;
   
   // Data bus
   assign oe = (!cs) && rw;
   assign data_out = addr[4] ? resolution_register : {4'b0, palette[addr[3:0]]};

   reg [1:0] speed_divider;
   
   // Generate 16MHz and 8MHz pixel clocks from 32MHz clock
   always @(posedge CLOCK_32) begin
      speed_divider <= speed_divider + 2'b1;
   end
   
   initial begin
      load_detect = 0;
      load_detect_delay = 0;
   end
   
   // Shift registers for detecting edges/levels
   always @(posedge CLOCK_32) begin
      de_state <= {de_state[0], de};
      load_state <= {load_state[0], load};
   end   

   initial begin
      pixel_count = 0;
      pixel_counter_enable = 0;
      load_detect = 0;
      load_detect_delay = 0;
      load_count = 4'b0;
   end
   
   always @(posedge CLOCK_32) begin
      // Count loads by shifting ones into this shift register
      if (reload_delay) begin
         load_count <= 4'b0000;
      end else if (load_state == `RISING) begin
         load_count <= {load_count[2:0], 1'b1};
      end
   end
   
   wire pixel_clock = resolution == 2 ? CLOCK_32 :
      (resolution == 1 ? speed_divider[0] : speed_divider[1]);
   
   // shifter reload
   reg reload;
   always @(posedge pixel_clock) begin
      if (load_count[3] && pixel_count == 4'b1111) begin
         reload = 1;
      end else begin
         reload = 0;
      end
   end
   
   // reload delay
   reg reload_delay;
   always @(pixel_clock or reset or reload) begin
      if (reset) begin
         reload_delay = 1;
      end else begin
         reload_delay = reload;
      end
   end
   
   // load detect
   reg load_detect;
   always @(posedge CLOCK_32) begin
      if (de_state == `LOW) begin
         load_detect = 0;
      end else if (load_state == `RISING) begin
         load_detect = 1;
      end
   end
   
   reg load_detect_delay;
   always @(pixel_clock or load_detect) begin
      if (pixel_clock) begin
         load_detect_delay = load_detect;
      end
   end

   reg pixel_counter_enable;
   always @(load_detect_delay or reload or reset) begin
      if (reset) begin
         pixel_counter_enable = 0;
      end else if (load_detect_delay) begin
         pixel_counter_enable = 1;
      end else if (reload) begin
         pixel_counter_enable = load_detect_delay;
      end
   end
   
   // shifter pixel count
   reg [3:0] pixel_count;
   
   always @(posedge pixel_clock) begin
      if (pixel_counter_enable) begin
         pixel_count <= pixel_count + 4'b1;
      end else begin
         // This is 4 in the real ST, but in this verilog model, with 4 some instances
         // of the "every other 16 pixels background" error can be seen in some wakestate(s) due to
         // the pixel counter reaching 15 one cycle earlier than expected.
         // With 3, spectrum 512 displays black dots that are caused by the palette updates
         // not arriving in time.
         // With this setting at 2, everything seems to work.
         pixel_count <= 4'd2;
      end
   end
   
   // shifter pixel count
   reg shifter_running;
   reg first_load_seen;
   reg [2:0] loads_seen;
   
   always @(posedge pixel_clock) begin
      if (reload_delay) begin
         // Refill shifter when empty
         shift_rr[0] <= shift_ir[0];
         shift_rr[1] <= shift_ir[1];
         shift_rr[2] <= shift_ir[2];
         shift_rr[3] <= shift_ir[3];
      end else begin
         // normal shift
         if (resolution == 0) begin
            // lo-res, every 4th clock
            shift_rr[0] <= {shift_rr[0][14:0], 1'b0};
            shift_rr[1] <= {shift_rr[1][14:0], 1'b0};
            shift_rr[2] <= {shift_rr[2][14:0], 1'b0};
            shift_rr[3] <= {shift_rr[3][14:0], 1'b0};      
         end else if (resolution == 1) begin
            // Medium res, every 2nd clock
            shift_rr[0] <= {shift_rr[0][14:0], shift_rr[2][15]};
            shift_rr[1] <= {shift_rr[1][14:0], shift_rr[3][15]};
            shift_rr[2] <= {shift_rr[2][14:0], 1'b0};
            shift_rr[3] <= {shift_rr[3][14:0], 1'b0};      
         end else begin
            // Monochrome, every clock
            shift_rr[0] <= {shift_rr[0][14:0], shift_rr[1][15]};
            shift_rr[1] <= {shift_rr[1][14:0], shift_rr[2][15]};
            shift_rr[2] <= {shift_rr[2][14:0], shift_rr[3][15]};
            shift_rr[3] <= {shift_rr[3][14:0], 1'b0};
         end
      end
   end
   
   always @(posedge CLOCK_32) begin
      // Register writes. RW=LOW. CS is asserted low also.
      if (!cs && !rw) begin
         if (addr == 16) begin
            resolution_register <= data;
         end else begin
            palette[addr[3:0]] <= data[11:0];
         end
      end
      
      // Load shifter
      if (load_state == `RISING && cs) begin
         // Shift them all over by one
         shift_ir[3] <= data;
         shift_ir[2] <= shift_ir[3];
         shift_ir[1] <= shift_ir[2];
         shift_ir[0] <= shift_ir[1];
      end
   end
   
   
   
endmodule


This probably still contains mistakes, but it does function well generally (e.g. PP menu #1 v2 gives it a bit of exercise).

User avatar
troed
Atari God
Atari God
Posts: 1398
Joined: Mon Apr 30, 2012 6:20 pm
Location: Sweden

Re: SHIFTER reimplementation on FPGA

Postby troed » Tue Jun 26, 2018 3:18 pm

Thanks! That was massively interesting. Esp. the every other 16 and Speccy black dots comment.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: SHIFTER reimplementation on FPGA

Postby Smonson » Tue Jun 26, 2018 3:50 pm

No problem, it's basically Ijor's work laid out in verilog. Apart from the bugs, those are all my own work :lol:

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: SHIFTER reimplementation on FPGA

Postby ijor » Tue Jun 26, 2018 5:44 pm

Congratulations! I'll try to make some comments later, but this is just great!

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: SHIFTER reimplementation on FPGA

Postby Smonson » Wed Jun 27, 2018 12:51 am

Thanks Ijor!

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: SHIFTER reimplementation on FPGA

Postby ijor » Wed Jun 27, 2018 2:50 am

Smonson wrote:This is fairly stable now, so I'm sharing the verilog model that I'm using.
Spectrum 512 works as long as the pixel count initial value is changed from 4 to 2.


This is probably because you are missing some pipeline cycles between the shift array and the palette lookup. But note that there is no ideal model here. Some programs with Spectrum 512 effects don't work correctly on a real Shifter depending on the wakeup. Furthermore, there is some async behaviour that might even be non deterministic and affected by such things as the temperature.

Code: Select all

resolution_register <= data;


Ideally this should be cleared on RESET. Not sure if any program actually depends on this, but this is what SHIFTER does.

Code: Select all

wire reset = load_state == `RISING && !cs;


Reset is whenever both signals are asserted (low), not just on the raising edge of LOAD. Might produce a slightly different behavior.

Code: Select all

   reg [1:0] speed_divider;
   // Generate 16MHz and 8MHz pixel clocks from 32MHz clock
   always @(posedge CLOCK_32) begin
      speed_divider <= speed_divider + 2'b1;
   end
      
   wire pixel_clock = resolution == 2 ? CLOCK_32 :
      (resolution == 1 ? speed_divider[0] : speed_divider[1]);
...   
   always @(posedge pixel_clock) begin
...
   always @(pixel_clock or reset or reload) begin


As we mentioned some time ago, it is not a very good idea to implement a clock mux like that. And it is not good practice to use the same signal as a clock and as data. The best method is to use the signal as clock enable, not directly as a clock. But if you insist, the FPGA has some dedicated hardware for clock muxing that you might be able to use.

I can infer from your code that you are not simulating the design. It is a bit of a PITA to perform simulations, but trust me, it is worth.

User avatar
Smonson
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 119
Joined: Sat Feb 20, 2016 9:45 am
Location: Canberra
Contact:

Re: SHIFTER reimplementation on FPGA

Postby Smonson » Wed Jun 27, 2018 3:02 am

Thanks for the comments Ijor. I'll reply in detail later when I have a PC in front of me, , but as for this one...

ijor wrote:

Code: Select all

wire reset = load_state == `RISING && !cs;


Reset is whenever both signals are asserted (low), not just on the raising edge of LOAD. Might produce a slightly different behavior.


I tried to implement it that way originally, but it doesn't work with spectrum 512 and others that write to shifter registers during the scanline.

ijor
Hardware Guru
Hardware Guru
Posts: 3398
Joined: Sat May 29, 2004 7:52 pm
Contact:

Re: SHIFTER reimplementation on FPGA

Postby ijor » Wed Jun 27, 2018 3:21 am

Smonson wrote:
ijor wrote:Reset is whenever both signals are asserted (low), not just on the raising edge of LOAD. Might produce a slightly different behavior.

I tried to implement it that way originally, but it doesn't work with spectrum 512 and others that write to shifter registers during the scanline.


That should not happen, they never overlap except on RESET. They are, at least, one 16MHz cycle apart (so more than one 32 MHz cycle). May be you used something like this:

Code: Select all

   wire reset = load_state == `LOW && !cs;


That is not correct because load_state is registered and cs is not (Did I mention it is worth to simulate ?) :)

In the worst case you might use a counter and trigger reset only if both are asserted together after so many cycles. But honestly, it's not that important.


Social Media

     

Return to “Coding”

Who is online

Users browsing this forum: No registered users and 1 guest