RFC - please dissect my design on a 6502 + VGA

For discussing the 65xx hardware itself or electronics projects.
User avatar
BigDumbDinosaur
Posts: 9428
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: RFC - please dissect my design on a 6502 + VGA

Post by BigDumbDinosaur »

ThePhysicist wrote:
Two steps back, one step forward...Honestly, I had to swallow hard when I saw the overhead c created...
C is not a good fit to the 6502 and is only a slightly better fit to the 65C02. The only member of the 6502 family that works reasonably well as a C target is the 65C816, primarily because of its more advanced stack handling, as well as other features that are friendlier to a C compiler.

If you are working at the bare metal, as you are doing, you really need to get up to speed with assembly language. Once you get over the hurdle of understanding the 6502 idiom you'll be amazed at how well you can translate your thoughts into working code.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

BigDumbDinosaur wrote:
C is not a good fit to the 6502 and is only a slightly better fit to the 65C02. The only member of the 6502 family that works reasonably well as a C target is the 65C816, primarily because of its more advanced stack handling, as well as other features that are friendlier to a C compiler.

If you are working at the bare metal, as you are doing, you really need to get up to speed with assembly language. Once you get over the hurdle of understanding the 6502 idiom you'll be amazed at how well you can translate your thoughts into working code.
I completely agree with you - and actually was aware of "issues" even before I started that. Still I wanted to go with c, simply because I've been doing it for 35 years. I even programmed c64 in c. Old habits are hard to break :oops:
No simulation survives contact with reality!
BillG
Posts: 710
Joined: 12 Mar 2020
Location: North Tejas

Re: RFC - please dissect my design on a 6502 + VGA

Post by BillG »

ThePhysicist wrote:

Code: Select all

C0DD A9 09            lda     #$09                 	lda #$09	;# tmp98,
C0DF C5 04            cmp     $04                  	cmp _r0		;# tmp98, a
C0E1 A9 00            lda     #$00                 	lda #$00	;# tmp98,
C0E3 E5 05            sbc     $05                  	sbc _r1		;# a
C0E5 50 02            bvc     LC0E9                	bvc L@9		;#
C0E7 49 80            eor     #$80                 	eor #$80	; negate top bit
                                                   L@9:
                                                   ;# firmware_v01_monitor_and_lcd_cc65.c:119:         return('A'-9 + a);
C0E9 08               php                          	php
C0EA A5 04            lda     $04                  	lda _r0		;# <retval>, a
C0EC 28               plp                          	plp
                                                   ;# firmware_v01_monitor_and_lcd_cc65.c:118:     if(a>9)
C0ED 10 06            bpl     LC0F5                	bpl L@7		;#
From another project, I immediately recognized that as a signed 16-bit comparison. If anyone knows of a better way to do that, I'm all ears.

A signed 16-bit comparison is definitely overkill for what you are doing. Try declaring a as unsigned char or just char and see whether the code improves.

Code: Select all

/* convert 4bit int to hex char */
const char int4_to_hexchar(unsigned char a)
{
    if(a>9)
        return('A'-9 + a);
    else
        return('0' + a);
}
John West
Posts: 383
Joined: 03 Sep 2002

Re: RFC - please dissect my design on a 6502 + VGA

Post by John West »

ThePhysicist wrote:

Code: Select all

    while(c=acia_getc() != '\x0d')
That doesn't mean what you wanted it to mean. != has higher precedence than =, so it's doing the comparison first, then assigning the result of the comparison (either 0 or 1) to c. It should be

Code: Select all

    while((c=acia_getc()) != '\x0d')
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

John West wrote:
ThePhysicist wrote:

Code: Select all

    while(c=acia_getc() != '\x0d')
That doesn't mean what you wanted it to mean. != has higher precedence than =, so it's doing the comparison first, then assigning the result of the comparison (either 0 or 1) to c. It should be

Code: Select all

    while((c=acia_getc()) != '\x0d')
UPPPS .... :oops:

thanks!
No simulation survives contact with reality!
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

Now that I solved my monitor problem I went back to the drawing board to give more details to the design of the VGA generator. Here is a block diagram I came up with:
vga_base_v02.jpg
In a second step I detailed it out in KiCAD.
vga_base.jpg
PDFs both in color and BW are attached.

Theory of operation:
I have 3 static RAMs. One holds sync information, the other two 6bit video signals (2 bit for each color). Each RAM can either be addressed by a counter, or by the 19 bit address bus. X and Y counters are created by 22V10 (10 bit counter each). I decided to give each of the 3 RAMS its own counter pair rather then routing the signals and separating them via 245 chips. The address bus is separated from the RAMs by three 74F245 (or 74HC245) chips. The counters have separate output enable controls.
All RAMs 'share' a databus, but again 74F245 chips will separate the bus into segments.
The 163 counters at the output are simply used as registers (they never count) - but I can use their CLEAR signals to enforce complete blanking.
During operation the main CPU first sets up the sync ram. This RAM generates both H-sync and V-sync for VGA and resets the X and Y counters. At any given time one data RAM provides in parallel to the sync RAM all information needed to display the signal. CPU (and additional block-copy hardware) will set up the new image in the second ram, then the 2 data RAMS switch places and the next round begins.
For the switch I probably will need some additional flip/flop to prevent switching in the mid of drawing a picture.

comments?
Attachments
vga_base_bw.pdf
(413.94 KiB) Downloaded 68 times
vga_base.pdf
(421.08 KiB) Downloaded 76 times
No simulation survives contact with reality!
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

babysteps... or baby crawl?

I added a 74HC574 buffer to the computer.
test_574_usage_schematic.jpg
A 74HC237 3-to-8 decoder is attached to address line 0-2, as well as clock and R/W signal. The final piece comes from the GAL controlling the memory layout. Any access to address 0x0340 should trigger output line 0 of the 237 decoder. This in turn would on the rising edge trigger the 574 buffer and store the contents from the 6502 databus.
Worked like a charm, EXCEPT.... the output of bits 0 and 1 ALWAYS was 1.
Analyses with the oscilloscope soon showed the reason though. When writing 00 to 0x0340 I got these images
adressbit4_hc237.jpg
Bit 4 looks as expected, but Bit 0 shows
adressbit0_hc237.jpg
that the data lines are still high from previous operation (sta #$00 #$0340). Solution - swap out the HC237 which gives an active HIGH signal with an 74HC138 which is active LOW. The 574 will still act on the rising edge, but that happens now half a cycle later. Here are oszi-trace of bit 0 and bit 4 when writing 0xF0 to the port:
adressbit0_hc138.jpg
adressbit4_hc138.jpg
The bits seem to stay up through the next half cycle, so I hope this will work.
No simulation survives contact with reality!
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

Update time. I finally finished my wiring on the breadboard. The final layout has 4 blocks:
cabling_v1_explained.jpg
On top I have a DAC. Two 74F245 chips select from which of the 2 video memories data is transferred to the three 74F163 chips. Those counters are only used as buffer, to ensure data remains unchanged until next clock pulse.
There are 3 blocks for sync memory (generates Hsync/Vsync/Blank signals as well as counter), video buffer 1 and video buffer 2. They are pretty identical. One 10-bit counter for X, one 9 bit counter for y. Three 74F245 allow to alternatively set memory addresses from the CPU. Another 245 chip regulates access via the general databus.
cabling_v1_explained_b.jpg
The three blocks are connected by 2 buses - one for address and one for data. 8 bit of the address bus are implemented via a 74F574 chip, the remaining 11 will come from the CPU directly. There is one control chip (another 574) to regulate which counters/245 blocks are used at any given time.

Next step - take out a multimeter and test all connections :)
No simulation survives contact with reality!
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

So after fixing a few missing connections I powered up the complete system - and had to find the 6502 was not working anymore. The reason was soon discovered - simply not enough power, the 5V powerline at the 6502 only showed 3.6V. With a 4A power supply and some power lines that problem was quickly solved - or so I thought.
At the next try I measured 4.7V - but still no luck. So I ripped out both data and address bus and a number of other cables, until the CPU started working again. Slowly extending the Databus finally pointed me to the first (of probably a few) design errors. I had wired the R/W signal to allow both reading and writing to/from the 3 RAM chips. With a 574 chip controlling the 245 arrays that separate the chips from the common bus.
What I had overlooked was to ensure at reset to initialize that 574 register correctly. So I got bus contention, and execution was halted.
Workaraound for the moment - I pull the R/W line low all the time to allow for further debugging. Therefore the RAM chips will not write to the bus. Some redesign will necessary later :)
No simulation survives contact with reality!
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: RFC - please dissect my design on a 6502 + VGA

Post by Dr Jefyll »

ThePhysicist wrote:
Slowly extending the Databus finally pointed me to the first (of probably a few) design errors.
Glad you're making progress! For future reference, be on the lookout for chips that seem to be running hot (especially when the supply current seems excessive). These are clues that might possibly have hastened discovery of the contention issue.

-- Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

Even after fixing the problem with bus contention my computer still would not boot each time correctly. That caused some head banging - until I noticed that the problems would not go away even if neither address- nor data-bus nor any control lines were connected. The problem persisted as soon as the power lines were connected. So I concluded my power distribution is not clean enough. I routed therefore 2 thick cables around the breadboards, and connected each short power strip at least twice to the main lines. And hurra - the system now boots successfully even when completely wired.

I also wrote code to initialize the sync ram. For each pixel in a 640x350 image (or 800x449 pixel including the porches) I have one byte in the sync ram - fitting neatly in 10bit x and 9 bit y counters, aka 19bit (512kbyte) DRAM. The same bytes also generate counter signals for y, reset for x and y counters and the blank signal. The bits are defined as:

Code: Select all

hsync        bit 0
vsync        bit 1
Blank        bit 2
not used
not used
yreset       bit 5
y-clock      bit 6
xreset       bit 7
All bits except hsync default to logic low. The definition of the VGA signal I want to create is:

Code: Select all

Scanline part  Pixels
Visible area   640
Front porch     16
Sync pulse      96
Back porch      48
Whole line     800

Vertical timing (frame)   
Polarity of vertical sync pulse is positive.   
Frame part   Lines
Visible area   400
Front porch     12
Sync pulse       2
Back porch      35
Whole frame    449
That means some of the building blocks are larger than 256 lines and do not fit into a single byte. So I split all of them into groups

Code: Select all

	Horizontal >>	Visible area  Visible area  Visible area  Front Porch   Sync Pulse    Back Porch   Back Porch       Fillup
v Vertical v    0/0  |  255           511           639           655           751           767          798           1023
---------------------------------------------------------------------------------------------------------------------------------
Visible area    255  |  1             1             1             5             4             5            5             197
Visible area    399  |  1             1             1             5             4             5            5             197
Front porch     411  |  5             5             5             5             4             5            5             197
Sync pulse      413  |  7             7             7             7             6             7            7             199
Back porch      448  |  5             5             5             5             4             5            5             197
Fillup          511  |  165           165           165           133           133           165          165           229
For instance - I have a visible block going from x=0/y=0 to x=255/y=255 and all the bytes in that block must be equal to 1. Another block goes from x=0/y=256 to x=255/y=399. And so on.

This is the code I came up with:

Code: Select all

loop3:                          ;--------------------------------------|
    ldy VGA_Y_BLK_INDEX         ; which Y group are we working on?     |
    lda YVALS,y                 ; load the number of lines             |
    clc                         ;                                      |
    adc VGA_TARGET_Y            ; add new number of lines to target    |
    sta VGA_TARGET_Y            ;                                      |
                                ;                                      |
loop2:                          ; ---------------|------------|        |
    stx VGA_Y_REG               ;                |            |        |
    ldy VGA_X_BLK_INDEX         ;                |            |        |
    lda (VGA_SYNC_DATA),y       ;                |            |        |
    pha                         ;                |            |        |
    lda (VGA_XBLKS),y           ;                |            |        |
    sta VGA_CUR_X_BLK_VALUE     ;                |            |        |
    tay                         ;                |            |        |
    pla                         ;                | loop       | loop   | loop
loop1:                          ;                | over       | over   | over
    sta (VGA_VIDMEM_PTR),y      ;--| main loop   | all        | all    | all
    DEY                         ;  | over single | X groups   | lines  | y
    bne loop1                   ;--| X group     | in         | in     | groups
    lda VGA_VIDMEM_PTR          ;                | single     | single |
    clc                         ;                | Y line     | y      |
    adc VGA_CUR_X_BLK_VALUE     ;                |            | group  |
    sta VGA_VIDMEM_PTR          ;                |            |        |
    bne noincp                  ;                |            |        |
    inc VGA_VIDMEM_PTR+1        ;                |            |        |
    noincp:                     ;                |            |        |
    inc VGA_X_BLK_INDEX         ;                |            |        |
    lda VGA_X_BLK_INDEX         ;                |            |        |
    cmp #8                      ;                |            |        |
    bne loop2                   ; ---------------|            |        |
    lda VGA_VIDMEM_PTR_SAVEL    ; restore VGA_VIDMEM_PTR      |        |
    sta VGA_VIDMEM_PTR          ; to saved value              |        |
    lda VGA_VIDMEM_PTR_SAVEH    ;                             |        |
    sta VGA_VIDMEM_PTR+1        ;                             |        |
    lda #0                      ; set X-group index to 0      |        |
    sta VGA_X_BLK_INDEX         ;                             |        |
    inx                         ; increase line counter       |        |
    bne SKIPINCREASE_LC         ; in case y lines roll over   |        |
    lda VGA_VIDMEM_PTR_SAVEH    ; increase high byte of       |        |
    clc                         ; VGA_VIDMEM_PTR_SAVE by 4    |        |
    adc #4                      ;                             |        |
    sta VGA_VIDMEM_PTR_SAVEH    ;                             |        |
SKIPINCREASE_LC:                ;                             |        |
    cpx VGA_TARGET_Y            ;                             |        |
;    brk                        ;                             |        |
;    nop                        ;                             |        |
;    nop                        ;                             |        |
    bne loop2                   ; ----------------------------|        |
    lda #'x'                    ;                                      |
    jsr printChar               ;                                      |
    lda VGA_SYNC_DATA           ; increase VGA SYNC_DATA               |
    clc                         ; pointer to next row                  |
    adc #8                      ;                                      |
    sta VGA_SYNC_DATA           ;                                      |
    inc VGA_Y_BLK_INDEX         ; increase Y block index               |
    lda VGA_Y_BLK_INDEX         ;                                      |
    cmp #6                      ; if still blocks to work, loop        |
    bne loop3                   ; -------------------------------------|
    jsr printEOL

    .linecont       +               ; Allow line continuations
XVALS:           .byte 0,0,128,16,96,16,31,225
YVALS:           .byte 0,144,12,2,35,63
DATA:            .byte 1,1,1,5,4,5,5,197,        \
                  1,1,1,5,4,5,5,197,        \
                  5,5,5,5,4,5,5,197,        \
                  7,7,7,7,6,7,7,197,        \
                  5,5,5,5,4,5,5,197,        \
                  165,165,165,133,133,165,165,229
Any suggestions how to improve on hat would be welcome!
No simulation survives contact with reality!
Martin A
Posts: 197
Joined: 02 Jan 2016

Re: RFC - please dissect my design on a 6502 + VGA

Post by Martin A »

ThePhysicist wrote:
Any suggestions how to improve on hat would be welcome!
If you're using the same screen mode all the time, would a pre-programmed flash rom be suitable? Save having to code anything ?
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

Quote:
If you're using the same screen mode all the time, would a pre-programmed flash rom be suitable? Save having to code anything ?
access speed - from what I researched ROM is simply to slow for 25MHz. And the "possibility" of programming a different resolution is also a nice to have.
No simulation survives contact with reality!
Andy201
Posts: 4
Joined: 02 Oct 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by Andy201 »

Dr Jefyll wrote:
ThePhysicist wrote:
Slowly extending the Databus finally pointed me to the first (of probably a few) design errors.
Glad you're making progress! For future reference, be on the lookout for chips that seem to be running hot (especially when the supply current seems excessive). These are clues that might possibly have hastened discovery of the contention issue.

-- Jeff
Yeah, that's a mistake I learnt at my own cost! Then I started using simulators which made me rethink about my assumptions about my designs. Simulators save heaps of time :)
ThePhysicist
Posts: 60
Joined: 17 Jun 2020

Re: RFC - please dissect my design on a 6502 + VGA

Post by ThePhysicist »

Update after a long long debugging session ..... I came up with a very strange error in my GAL (Atmel 22V10C) used for chip selection.

Code: Select all

Name     mk01 GAL MAIN ;
PartNo   Lattice22V10B;
Date     6/27/2020 ;
Revision 01 ;
Designer HM ;
Company  private ;
Assembly None ;
Location None ;
Device   g22v10;

/*
 * Lattice GAL 22V10B pinout, DIP, top view
 *
 * I/CLK.[ 1     24 ].VCC
 *     I.[ 2     23 ].I/O/Q
 *     I.[ 3     22 ].I/O/Q
 *     I.[ 4     21 ].I/O/Q
 *     I.[ 5     20 ].I/O/Q
 *     I.[ 6     19 ].I/O/Q
 *     I.[ 7     18 ].I/O/Q
 *     I.[ 8     17 ].I/O/Q
 *     I.[ 9     16 ].I/O/Q
 *     I.[ 10    15 ].I/O/Q
 *     I.[ 11    14 ].I/O/Q
 *   GND.[ 12    13 ].I
 *
 *
 * 0x0000 - 0x00FF	0000:0000:0000:0000 - 0000:0000:1111:1111		Page Zero	RAM
 * 0x0100 - 0x01FF	0000:0001:0000:0000 - 0000:0001:1111:1111		Stack		RAM
 * 0x0200 - 0x02FF	0000:0010:0000:0000 - 0000:0010:1111:1111		Variables	RAM
 * 0x0300 - 0x030F	0000:0011:0000:0000 - 0000:0011:0000:1111		VIA1		VIA1
 * 0x0310 - 0x031F	0000:0011:0001:0000 - 0000:0011:0001:1111		VIA2		VIA2
 * 0x0320 - 0x032F	0000:0011:0010:0000 - 0000:0011:0010:1111		ACIA1		ACIA1
 * 0x0330 - 0x033F	0000:0011:0011:0000 - 0000:0011:0011:1111		ACIA2		ACIA2
 * 0x0340 - 0x035F	0000:0011:0100:0000 - 0000:0011:0101:1111		32 74F574	CTRL
 * 0x0360 - 0x03FF	0000:0011:0110:0000 - 0000:0011:1111:1111		reserved	CTRL
 * 0x0400 - 0x7FFF	0000:0100:0000:0000 - 0111:1111:1111:1111		memory		RAM
 * 0x8000 - 0xBFFF	1000:0000:0000:0000 - 1011:1111:1111:1111		16kb window	WINDOW
 * 0xC000 - 0xFFFF	1100:0000:0000:0000 - 1111:1111:1111:1111 	16kb ROM	ROM
 *
 *
 * Inputs
 */

/* *************** INPUT PINS *********************/
PIN  1  =  PHI2                   ; /*                                 */ 
PIN  2  =  RW                     ; /*                                 */ 
PIN  3  =  A04                    ; /*                                 */ 
PIN  4  =  A05                    ; /*                                 */ 
PIN  5  =  A06                    ; /*                                 */ 
PIN  6  =  A07                    ; /*                                 */ 
PIN  7  =  A08                    ; /*                                 */ 
PIN  8  =  A09                    ; /*                                 */ 
PIN  9  =  A10                    ; /*                                 */ 
PIN 10  =  A11                    ; /*                                 */ 
PIN 11  =  A12                    ; /*                                 */ 
PIN 13  =  A13                    ; /*                                 */ 
PIN 14  =  A14                    ; /*                                 */ 
PIN 15  =  A15                    ; /*                                 */ 


/* *************** OUTPUT PINS *********************/
PIN 16  =  N_VIA1                 ; /*                                 */ 
PIN 17  =  N_VIA2                 ; /*                                 */ 
PIN 18  =  N_ACIA1                ; /*                                 */ 
PIN 19  =  N_RAM                  ; /*                                 */ 
PIN 20  =  CTRL                   ; /*                                 */ 
PIN 21  =  N_WINDOW               ; /*                                 */ 
PIN 22  =  N_ROM                  ; /*                                 */ 
PIN 23  =  N_ACIA2                ; /*                                 */ 

/* Main */

RD     =  RW                      ;
ROM    =  A15 &  A14 & PHI2 & RD  ;
WINDOW =  A15 & !A14 & PHI2       ;

ALLCTRL=  !A15 & !A14 & !A13 & !A12 & !A11 & !A10 &  A09 &  A08       ;
VIA1   =  ALLCTRL & !A07 & !A06 & !A05 & !A04                         ;
VIA2   =  ALLCTRL & !A07 & !A06 & !A05 &  A04                         ;
ACIA1  =  ALLCTRL & !A07 & !A06 &  A05 & !A04                         ;
ACIA2  =  ALLCTRL & !A07 & !A06 &  A05 &  A04                         ;
CTRL   =  ALLCTRL & !VIA1 & !VIA2 & !ACIA1 & !ACIA2                   ;

RAM    =  !ROM & !WINDOW & !ALLCTRL                             & PHI2;

N_VIA1   = !VIA1;
N_VIA2   = !VIA2;
N_RAM    = !RAM;
N_ROM    = !ROM;
N_ACIA1  = !ACIA1;
N_ACIA2  = !ACIA2;
N_WINDOW = !WINDOW;
With this code - whenever I put anything (even just an OSZI probe) on pin 21 (aka !WINDOW), the whole systems becomes erratic (probably only for the code that activates !WINDOW). LEDs active only for short amounts of time drop in intensity over the whole system (I suspect the average time they are on drops), and the code starts to behave differently. Now the bummer - if I change that last line to

Code: Select all

N_WINDOW = WINDOW;
everything behaves as expected.
Any ideas welcome :)
No simulation survives contact with reality!
Post Reply