VideoNuLA and 6845 questions

discuss both original and modern hardware for the bbc micro/electron
Post Reply
amb5l
Posts: 7
Joined: Thu Mar 12, 2020 11:09 am
Contact:

VideoNuLA and 6845 questions

Post by amb5l » Fri Mar 20, 2020 1:58 pm

Hi all

I am working on (yet another) BBC clone on an FPGA. I have some questions about RobC's VideoNuLA upgrade, and the 6845.

@RobC do you mind if I implement compatibility with your VideoNuLA? Can you share the programming details?

I am trying to understand "rupture" smooth vertical scrolling. I've seen some useful info on an Amstrad CPC464 forum, but would appreciate if anyone could check my understanding of a typical use case:

- divide screen into 3 vertical regions:
- 1 at top, small, static
- 2 in middle, large, smooth (and hardware) scrolling
- 3 at bottom, small, static

Sequence of events:
  1. vertical sync occurs, vertical sync interrupt handler executes:
    - sets up region 1 timer interrupt to fire just after start of visible portion of region 1 (after R12,R13 values have been used)
  2. 6845 reaches end of previous field, reloads counters from registers (which are already set up for region 1), starts displaying region 1
  3. region 1 timer interrupt occurs, sets up 6845 for region 2:
    - R4 (vertical total) = N rows for region 2 e.g. 27
    - R5 (vertical total adjust) = 7-x, where x = R5 value used for region 1 of previous field, see below
    - R6 (vertical displayed) = R4 value above
    - R7 (vertical sync position) = illegally large value?
    - R12,R13 = memory location of region 2
    - finishes by setting up region 2 timer interrupt to fire just after start of visible portion of region 2
  4. 6845 reaches end of region 1, reloads counters from registers, starts displaying region 2
  5. region 2 timer interrupt occurs, sets up 6845 for region 3:
    - R4 (vertical total) = 39-x, where x = R4(1) + R4(2) + 1
    - R5 (vertical total adjust) = 0; we want 39 rows exactly for whole screen
    - R6 (vertical displayed) = 32-x, where x = R6(1) + R6(2) + 1
    - R7 (vertical sync position) = 34-x, where x = R6(1) + R6(2) + 1; so vsync occurs at normal time
    - R12,R13 = memory location of region 3
    - finishes by setting up region 3 timer interrupt to fire just after start of visible portion of region 3
  6. 6845 reaches end of region 2, reloads counters from registers, starts displaying region 3
  7. region 3 timer interrupt occurs, sets up 6845 for region 1:
    - R4 (vertical total) = rows for region 1 e.g. 2
    - R5 (vertical total adjust) = 0-7 according to current smooth scroll position of region 2
    - R6 (vertical displayed) = R4 value above
    - R7 (vertical sync position) = illegally large value?
    - R12,R13 = memory location of region 1
  8. => back to step 1
Notes:
- (1) after a register means the value in that register for the previous region 1
- (2) after a register means the value in that register for region 2 of this field
- for some registers, the value programmed should be the number of rows - 1; in the text above the value given is always the number of rows

Presumably the memory area used for region 2 moves and wraps around within the overall video memory (10k, 20k etc). And region 1 and region 3 must likewise move around (to avoid being overwritten by region 2) and therefore be redrawn for each field - or can they be kept static outside the hardware scrolling memory?

If you've read this far - thanks!

cmorley
Posts: 1242
Joined: Sat Jul 30, 2016 8:11 pm
Location: Oxford
Contact:

Re: VideoNuLA and 6845 questions

Post by cmorley » Fri Mar 20, 2020 2:03 pm

Rob has posted a comprehensive manual which is enough to reimplement the functionality from. I believe hoglet reimplemented it in a project.

amb5l
Posts: 7
Joined: Thu Mar 12, 2020 11:09 am
Contact:

Re: VideoNuLA and 6845 questions

Post by amb5l » Fri Mar 20, 2020 2:08 pm

@cmorley thankyou, couldn't find it for looking. @RobC can I ask about the ROM - do you allow ROM images to be used in emulators and clones?

User avatar
tricky
Posts: 4245
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: VideoNuLA and 6845 questions

Post by tricky » Fri Mar 20, 2020 3:10 pm

You should look at some of Kieran's bitshifter's writeups.
In my experience, your regions 1 and 2 are combined but the top is hidden by disabling colour output.
All the registers < 12 take immediate (or nearly so) effect, only R12/13 are latched and loaded for the new frame/field.
Region 3 is usually placed outside of the wrapping area to avoid it having to be redrawn.
My AstroBlaster does this, Scramble is software scrolling, but still have ~30 6845 frame/fields per vsync.
For the latest demos, you need to get your timing and cycle stretching not only clock accurate but in some cases trailing/leading edge correct (IIRC).

amb5l
Posts: 7
Joined: Thu Mar 12, 2020 11:09 am
Contact:

Re: VideoNuLA and 6845 questions

Post by amb5l » Fri Mar 20, 2020 3:28 pm

@tricky thankyou that is valuable feedback. I've found a really good post by @kieranhj. It's going to be difficult to achieve cycle accurate emulation of the original hardware but that's one of my aims. And the demos/games you mention will go a long way to proving whether I've managed it.

User avatar
tricky
Posts: 4245
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: VideoNuLA and 6845 questions

Post by tricky » Fri Mar 20, 2020 4:38 pm

There are some differences between 6845s but I guess if you are emulating a single machine, you just need to pick one ;)
Most of my games do some 6845 poking, but not as advanced as Kieran's demos.

User avatar
kieranhj
Posts: 875
Joined: Sat Sep 19, 2015 11:11 pm
Location: Farnham, Surrey, UK
Contact:

Re: VideoNuLA and 6845 questions

Post by kieranhj » Fri Mar 20, 2020 5:43 pm

amb5l wrote:
Fri Mar 20, 2020 1:58 pm
I am trying to understand "rupture" smooth vertical scrolling. I've seen some useful info on an Amstrad CPC464 forum, but would appreciate if anyone could check my understanding of a typical use case:

- divide screen into 3 vertical regions:
- 1 at top, small, static
- 2 in middle, large, smooth (and hardware) scrolling
- 3 at bottom, small, static
I'm glad you found my previous post for (ab)using the CRTC useful. It covers vertical rupture and the smooth scrolling implementation.
amb5l wrote:
Fri Mar 20, 2020 1:58 pm
Sequence of events:
  1. vertical sync occurs, vertical sync interrupt handler executes:
    - sets up region 1 timer interrupt to fire just after start of visible portion of region 1 (after R12,R13 values have been used)
  2. 6845 reaches end of previous field, reloads counters from registers (which are already set up for region 1), starts displaying region 1
  3. region 1 timer interrupt occurs, sets up 6845 for region 2:
    - R4 (vertical total) = N rows for region 2 e.g. 27
    - R5 (vertical total adjust) = 7-x, where x = R5 value used for region 1 of previous field, see below
    - R6 (vertical displayed) = R4 value above
    - R7 (vertical sync position) = illegally large value?
    - R12,R13 = memory location of region 2
    - finishes by setting up region 2 timer interrupt to fire just after start of visible portion of region 2
Typically you would set up the 6845 registers for region 1 here, at the start of the region 1 display, apart from R12,R13 which are latched so should be set up for region 2. Because most of the 6845 registers are counter maximum values you need to set them to their new desired values before the internal counter == maximum comparison is triggered. In practice this typically means setting the desired values for the current CRTC display cycle (or region, as you're calling it here) at the very start of the cycle, whilst all of the internal counter values are still small.

So here, you'd ideally want your region 1 timer interrupt to trigger within the first character row (8 scanlines) then set the registers to what you want for region 1. Obviously the smaller you make your regions, the tighter the timing gets. Smooth scrolling with Vertical Adjust takes some getting your head around, so it's probably easier to think of the simpler 3x rupture case first.

For example, try a set up with region 1 = 2 rows static, region 2 = 28 rows scrolling with character addressing, region 3 = 2 rows static first.
amb5l wrote:
Fri Mar 20, 2020 1:58 pm
  • 6845 reaches end of region 1, reloads counters from registers, starts displaying region 2
  • region 2 timer interrupt occurs, sets up 6845 for region 3:
    - R4 (vertical total) = 39-x, where x = R4(1) + R4(2) + 1
    - R5 (vertical total adjust) = 0; we want 39 rows exactly for whole screen
    - R6 (vertical displayed) = 32-x, where x = R6(1) + R6(2) + 1
    - R7 (vertical sync position) = 34-x, where x = R6(1) + R6(2) + 1; so vsync occurs at normal time
    - R12,R13 = memory location of region 3
    - finishes by setting up region 3 timer interrupt to fire just after start of visible portion of region 3
As above, only R12,R12 registers are latched so the rest will take effect immediately as the == comparator. If you set the R7 Vertical Sync Position here then you'll get a vsync in the middle of your region 2. Remember that when the CRTC starts a new cycle, all of the internal counters are reset to 0 so any register values should take this into account relative to the start of the frame. I think you're considering that factor here with your (1) and (2) notation.
amb5l wrote:
Fri Mar 20, 2020 1:58 pm
[*]6845 reaches end of region 2, reloads counters from registers, starts displaying region 3
[*]region 3 timer interrupt occurs, sets up 6845 for region 1:
- R4 (vertical total) = rows for region 1 e.g. 2
- R5 (vertical total adjust) = 0-7 according to current smooth scroll position of region 2
- R6 (vertical displayed) = R4 value above
- R7 (vertical sync position) = illegally large value?
- R12,R13 = memory location of region 1
[*] => back to step 1
[/list]
Notes:
- (1) after a register means the value in that register for the previous region 1
- (2) after a register means the value in that register for region 2 of this field
- for some registers, the value programmed should be the number of rows - 1; in the text above the value given is always the number of rows
In general smooth vertical scrolling is quite tricky to get right and is much easier when the first (top) region is smooth scrolling and the one underneath it is fixed. The reason is that using R5 Vertical Adjust adds a number of scanlines to the end of the CRTC cycle - it will continue to display data in those scanlines as per your usual addressing. The following region will display RAM from R12,R13 starting at scanline 0 so to get the effect of scrolling the first N scanlines off the top of the region, you need to blank the display at a fixed vertical position. This is most easily accomplished by blanking the first 8 scanlines at the top of the first region at the start of the frame (since the overscan is black anyway). Turning off this blanking requires the tightest interrupt timing, the rest can be fairly loose depending on how big you want you regions to be.

Your proposed 3x region set up would actually have to look something like this:
  • Region 1: 2x character rows total + [0-7] extra scanlines added with Vertical Adjust
    • <--- super tight timing here to turn the display off after row 2 and back on after row 3 so you don't see the moving join
  • Region 2: 27x character rows total + (8 - [0-7]) scanlines added with Vertical Adjust but 28x rows displayed! (so data still feeds into the extra scanlines)
  • Region 3: 9x character rows total with 2x rows displayed and vsync at row 5.
amb5l wrote:
Fri Mar 20, 2020 1:58 pm
Presumably the memory area used for region 2 moves and wraps around within the overall video memory (10k, 20k etc). And region 1 and region 3 must likewise move around (to avoid being overwritten by region 2) and therefore be redrawn for each field - or can they be kept static outside the hardware scrolling memory?
Yes, that's correct. You can have any address you like for region 1 and 3, these can be static, or double-buffered, and don't even have to be within the regular range of &3000 - &8000. You're going to get wrap around at &8000 according to the screen size selected with the addressable latch. (See page 386 of the NAUG).
Bitshifters Collective | Retro Code & Demos for BBC Micro & Acorn computers | https://bitshifters.github.io/

amb5l
Posts: 7
Joined: Thu Mar 12, 2020 11:09 am
Contact:

Re: VideoNuLA and 6845 questions

Post by amb5l » Fri Mar 20, 2020 6:33 pm

@kieranhj fantastic - thank you very much for your input.

User avatar
scarybeasts
Posts: 318
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: VideoNuLA and 6845 questions

Post by scarybeasts » Sat Mar 21, 2020 12:06 am

amb5l wrote:
Fri Mar 20, 2020 3:28 pm
@tricky thankyou that is valuable feedback. I've found a really good post by @kieranhj. It's going to be difficult to achieve cycle accurate emulation of the original hardware but that's one of my aims. And the demos/games you mention will go a long way to proving whether I've managed it.
Cycle accurate emulation is definitely a worthy goal! And tricky as you note.
A cycle accurate NMOS 6502 is a well trodden path thanks to http://www.visual6502.org/
The 6522 and 6845 are both tricky beasts. I've done some work on trying to make the emulation of those closer to cycle accurate in jsbeeb. As far as I know, it's currently the most accurate beeb emulator in these areas, but I'm 100% sure there are corner cases not yet fully explored.

In case it helps: jsbeeb currently emulates the Hitachi 6845, as used in the model b, and hopefully the corner case discoveries are reasonably commented in video.js.


Cheers
Chris

RobC
Posts: 2812
Joined: Sat Sep 01, 2007 10:41 pm
Contact:

Re: VideoNuLA and 6845 questions

Post by RobC » Sat Mar 21, 2020 12:03 pm

amb5l wrote:
Fri Mar 20, 2020 1:58 pm
@RobC do you mind if I implement compatibility with your VideoNuLA? Can you share the programming details?
Hi - no problem with this. As others have said, hoglet has already done this using the details in the manual. I'd appreciate a name check if you release anything :D

I'm happy to try to answer any questions but my time is very limited at the moment (which is why I've not been on here much lately).

Out of interest, what sort of hardware are you targeting?
amb5l wrote:
Fri Mar 20, 2020 2:08 pm
@RobC can I ask about the ROM - do you allow ROM images to be used in emulators and clones?
Yes - the ROM is freely available. The latest version (v1.03) is attached - it has an additional command (*VNLOAD) to load palette files without going into the editor.

Best wishes,

Rob
Attachments
VideoNuLA 103.zip
(6.68 KiB) Downloaded 13 times

User avatar
hoglet
Posts: 9108
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: VideoNuLA and 6845 questions

Post by hoglet » Sat Mar 21, 2020 12:19 pm

RobC wrote:
Sat Mar 21, 2020 12:03 pm
Hi - no problem with this. As others have said, hoglet has already done this using the details in the manual. I'd appreciate a name check if you release anything :D
Yes, in case it's any use, my attempt at this is here:
https://github.com/hoglet67/BeebFpga/bl ... idproc.vhd

Dave

amb5l
Posts: 7
Joined: Thu Mar 12, 2020 11:09 am
Contact:

Re: VideoNuLA and 6845 questions

Post by amb5l » Sat Mar 21, 2020 8:40 pm

@RobC @hoglet thanks both.

I'm targeting a Digilent Nexys Video (Xilinx Artix-7) board at present, with custom hardware on the drawing board. My design is an evolving BBC clone/upgrade based around my own 6502 compatible CPU. It runs at ~50MHz, single cycle per instruction for everything except JMP indirect and read-modify-writes (which take 2 cycles). It has a very shallow pipeline to avoid branch penalties and issues with self modifying code. Some tricks include caching of vectors, zero page and the stack. This allows pointer fetches (for indirect indexed address modes) and stack pulls (for RTS/RTI) to happen concurrently with data reads/writes. Memory is tightly coupled to the CPU, and is dual ported so instruction and data access and happen together; each port can read or write up to 4 bytes per cycle (unaligned). DMA (e.g. CRTC access) is interleaved without penalty; the memory is clocked at 100MHz.

I am working on cycle level compatibility with the original NMOS 6502 now. My CPU instruction decoder includes details of how many cycles instructions should take on the NMOS original. This borrows an existing mechanism to halt/pause execution for debug/breakpoint purposes. It starts up in compatible mode and the user can then enable high speed execution.

I'm working on the 6845 and Video ULA at the same time because every now and then I need a break from the CPU which is frying my brain!

The background to this is my experience of hiring graduate electronic engineers. Something seems to be missing from our education system; I have encountered some candidates unable to answer basic questions (Ohm's law etc), with many demonstrating "knowledge without understanding".... My education was massively boosted by the mental workouts that my BBC micro gave me from my early teens. I would like to see something similar for today's generation, and I'm not sure the Raspberry Pi fits the bill because its hardware and software is the work of hundreds or even thousands of people... The Arduino comes close.

In a nutshell, I want to see 13+ year olds tackling VHDL and assembly language. So I'm working on my own ideas of something that could stimulate that. The more we can do to stimulate STEM education the better, right?

amb5l
Posts: 7
Joined: Thu Mar 12, 2020 11:09 am
Contact:

Re: VideoNuLA and 6845 questions

Post by amb5l » Sat Mar 21, 2020 8:44 pm

@scarybeasts thanks for the lead, I will look at your JS emulator. Am aware of visual6502 and am suitably impressed!

User avatar
scarybeasts
Posts: 318
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: VideoNuLA and 6845 questions

Post by scarybeasts » Sun Mar 22, 2020 12:38 am

amb5l wrote:
Sat Mar 21, 2020 8:44 pm
@scarybeasts thanks for the lead, I will look at your JS emulator. Am aware of visual6502 and am suitably impressed!
Note that jsbeeb was written by Matt Godbolt, not me. I contributed, including video emulation accurately, later on.


Cheers
Chris

amb5l
Posts: 7
Joined: Thu Mar 12, 2020 11:09 am
Contact:

Re: VideoNuLA and 6845 questions

Post by amb5l » Mon May 04, 2020 10:37 am

Hi again all,

Before I dive into the documentation, can anyone help with the following?

Video data fetch and serialise
Is the following correct for mode 0?
1) CRTC emits memory address and character scan number following 2MHz clock edge
2) DRAM controller fetches data byte from wrapped address; this takes 4x 16MHz clock cycles = 1x 2MHz cycle
3) data byte is sampled by video ULA at the next 2MHz clock edge
4) data is serialised by video ULA using 16MHz clock; MSB is driven immediately after the above 2MHz edge, lower bits follow it
So the combination of DRAM fetch and video ULA introduces a single 2MHz clock cycle of latency in the video path and sync etc timings are programmed accordingly.

DRAM refresh
Are the DRAM rows and columns mapped to CPU/CRTC addresses so that every DRAM row is hit by CRTC display refresh, even in mode 7? So that explicit DRAM refresh cycles are not required?

Thanks!

User avatar
1024MAK
Posts: 9906
Joined: Mon Apr 18, 2011 5:46 pm
Location: Looking forward to summer in Somerset, UK...
Contact:

Re: VideoNuLA and 6845 questions

Post by 1024MAK » Tue May 05, 2020 3:50 am

DRAM Refresh

The refresh of the DRAM is done purely by address lines A0 to A6 being cycled by the 6845 CRTC during it’s part of the cycle of access to the DRAM address bus. The 6845 CRTC does this regardless if any actual screen data is needed. Note that it’s the DRAM in a BBC model A or B that needs only A0 to A6, the 6845 CRTC is happy to cycle all its outputs.

The type of DRAM chips used require a 128 cycle (7 bit) at a minimum interval of 2ms (although in practice they can often retain their contents for rather longer than this). For refresh, the DRAM only need a row address (/RAS only refresh), hence why only seven address lines are needed.

Mark

Post Reply

Return to “8-bit acorn hardware”