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.
RFC - please dissect my design on a 6502 + VGA
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: RFC - please dissect my design on a 6502 + VGA
ThePhysicist wrote:
Two steps back, one step forward...Honestly, I had to swallow hard when I saw the overhead c created...
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
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.
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.
No simulation survives contact with reality!
Re: RFC - please dissect my design on a 6502 + VGA
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 ;#
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);
}
Re: RFC - please dissect my design on a 6502 + VGA
ThePhysicist wrote:
Code: Select all
while(c=acia_getc() != '\x0d')
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
John West wrote:
ThePhysicist wrote:
Code: Select all
while(c=acia_getc() != '\x0d')
Code: Select all
while((c=acia_getc()) != '\x0d')
thanks!
No simulation survives contact with reality!
-
ThePhysicist
- Posts: 60
- Joined: 17 Jun 2020
Re: RFC - please dissect my design on a 6502 + VGA
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:
In a second step I detailed it out in KiCAD.
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?
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 67 times
-
- vga_base.pdf
- (421.08 KiB) Downloaded 74 times
No simulation survives contact with reality!
-
ThePhysicist
- Posts: 60
- Joined: 17 Jun 2020
Re: RFC - please dissect my design on a 6502 + VGA
babysteps... or baby crawl?
I added a 74HC574 buffer to the computer. 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 Bit 4 looks as expected, but Bit 0 shows 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: The bits seem to stay up through the next half cycle, so I hope this will work.
I added a 74HC574 buffer to the computer. 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 Bit 4 looks as expected, but Bit 0 shows 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: 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
Update time. I finally finished my wiring on the breadboard. The final layout has 4 blocks:
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. 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
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. 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
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
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!
Re: RFC - please dissect my design on a 6502 + VGA
ThePhysicist wrote:
Slowly extending the Databus finally pointed me to the first (of probably a few) design errors.
-- Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
-
ThePhysicist
- Posts: 60
- Joined: 17 Jun 2020
Re: RFC - please dissect my design on a 6502 + VGA
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:
All bits except hsync default to logic low. The definition of the VGA signal I want to create is:
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
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:
Any suggestions how to improve on hat would be welcome!
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
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
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
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
No simulation survives contact with reality!
Re: RFC - please dissect my design on a 6502 + VGA
ThePhysicist wrote:
Any suggestions how to improve on hat would be welcome!
-
ThePhysicist
- Posts: 60
- Joined: 17 Jun 2020
Re: RFC - please dissect my design on a 6502 + VGA
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 ?
No simulation survives contact with reality!
Re: RFC - please dissect my design on a 6502 + VGA
Dr Jefyll wrote:
ThePhysicist wrote:
Slowly extending the Databus finally pointed me to the first (of probably a few) design errors.
-- Jeff
-
ThePhysicist
- Posts: 60
- Joined: 17 Jun 2020
Re: RFC - please dissect my design on a 6502 + VGA
Update after a long long debugging session ..... I came up with a very strange error in my GAL (Atmel 22V10C) used for chip selection.
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
everything behaves as expected.
Any ideas welcome
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;
Code: Select all
N_WINDOW = WINDOW;Any ideas welcome
No simulation survives contact with reality!