From left to right
Xilinx Spartan 3A - Used as the custom made VGA Controller - Called DANI-I VGA
Output is VGA @ 640x480 60Hz - but the pixel area is 320x240 or a 40x30 tile display of 8x8 tiles, with 16 sprites. 6bit Resistor DAC (64 Displayable colors) 2 Colors per 8x8 tile (for time being)
The the Right of that on bottom is 32Kb of Video RAM, it holds all the Tile and Sprite Data. Above that is the screen Index buffer and VGA command register which is 4k of Dual Port Ram. The Left port is accessed by the FPGA at 25mhz and Right side is accessed by the 6502 at 4mhz. During HSYNC optional commands can be sent to the VGA controller for storing or retrieving tile and sprite data, screen data can be accessed at any time.
In the middle is the address bus and data bus (I know im gonna get hate for doing this on a breadboard, but hey - it's what i had
Next starting on the bottom is the main system SRAM Chip, 32Kb of it - above it is some address decoding and glue logic.
In the next column we have a reset circuit on top - it consists of a Hex Inverter and a 555 circuit for reset.
Below the Hex Inverter is the 6502! (So glad I went with this chip - it's been amazing) Below the 6502 is the ROM it's 32Kb but only 16Kb of it is accessible.
On the far right is nothing special yet... it's just glue logic for the additional IC's i will be adding this week, including the 6522.
This is a line debugger I created to watch the address and data lines to debug issues.
My homemade EEPROM programmer
And Finally - the thing that made everything worth it this weekend - the DANI-I 6502 first test of actual code! The Memory map -
Code: Select all
$0000 - $7FFF => SRAM 32k b0.xxxxxxxxxxxxxxx
$8000 - $8FFF => VRAM 04k b1000.xxxxxxxxxxxx
$9000 - $90FF => ACIA 1b b10010000.xxxxxxxx
$9100 - $91FF => VIA 1b b10010001.xxxxxxxx
$9200 - $92FF => PIA 1b b10010010.xxxxxxxx
$C000 - $FFFF => ROM 16k b11.xxxxxxxxxxxxxx
Code: Select all
;-------------------------------------------------
;-------------DANI-I-SYSTEM-ROM-------------------
;-------------------------------------------------
;-------------EQUATES-----------------------------
VRAM: .SET $8000
VRAM_CMD: .SET VRAM + $F00
VRAM_CHARSLOC: .SET VRAM + $F10
VRAM_CHARSBUF: .SET VRAM + $F20
CURSOR_LOC: .SET $80 ; Cursor Location ZP: 40
;-------------EO-EQUATES--------------------------
.ORG $C000
RESET:
LDX #$FF ; Initialize the Stack Pointer
TXS ; Transfer X to Stack
START:
JSR SYS_INIT ; Initialize the System
LDA #<S_HelloWorld
STA $10
LDA #>S_HelloWorld
STA $11
JSR DVGA_PUTS ; Print out String
HALT:
JMP HALT ; Done: "halt" in an infinite loop
;----------SUB-ROUTINES---------------------------
;----------System Initialization -----------------
;-- Parameters - VOID
;-------------------------------------------------
SYS_INIT:
LDX #<[CHAR_ROM+$400-8] ; Store Low Byte of Char ROM (Last Character) in ZP 05
STX $40
LDX #>[CHAR_ROM+$400-8] ; Store High Byte of Char ROM (Last Character) in ZP 06
STX $41
LDX #$7F ; Set X counter to 127 (128 total)
.loop
STX $20 ; Set Location of this character
LDA $40 ; Set Address of Char Rom in ZP 40
STA $10
LDA $41
STA $11
JSR DVGA_STORECHAR ; Put Address of Character in ZP 10 and Location you want it stored in ZP 20
LDA #$08 ; Put 8 bytes of dec
STA $10 ; Store it in param (ZP10)
JSR MEM_SAFE_ZP40_DEC
DEX ; deduct 1 from the location
BPL .loop ; loop until we hit go through 0 to FF
JSR DVGA_BLANKSCREEN ; Blank the Screen
RTS
;----------Safe Memory Decrement -----------------
;-- Parameters - ZP10 = Amount to Dec ZP 40 by
;-------------------------------------------------
MEM_SAFE_ZP40_DEC:
PHA ; Store A
TXA ;
PHA ; Push X to Stack
LDX $10 ; Get the amount we want to dec by
.loop
DEC $40 ; Deduct from Memaddress 40
LDA $40 ; Test A
CMP #$FF
BEQ .deduct41 ; If we hit FF, make sure we deduct from 41
.cont
DEX ; Decrease X Counter
BNE .loop ; Loop if we arent at 0 yet
PLA ; Restore X
TAX
PLA ; Restore A
RTS ; Return from Sub
.deduct41
DEC $41 ; Deduct from High Byte
JMP .cont ; Go Back
;----------DVGA Store Character ------------------
;-- Parameters - ZP10 = Address of Character
;-- Paramaters - ZP20 = Location that you want to store charater in
;-------------------------------------------------
DVGA_STORECHAR: ;-- ptr to Character in ZP 10, stored in LDA, Location is in ZP 20
PHA ; Push A To Stack
TYA
PHA ; Push Y To Stack
LDY #$07 ; Set up counter - put 7
.loop: ; Start of Loop
LDA ($10),Y ; Get StoreChar Byte
STA VRAM_CHARSBUF,Y ; Store it in VRAM
DEY ; Decrement Y
BPL .loop ; Continue to loop until it wraps
LDA $20 ; Load location value
STA VRAM_CHARSLOC ; Store it in Vram Char location
LDA #$01 ; Set Store Command
STA VRAM_CMD ; in the VGA command location
.chkcmd:
; LDA VRAM_CMD ; Check to see if it was loaded in
; BNE .chkcmd ; It was? Okay were good
PLA
TAY ; Restore Y
PLA ; Restore A
RTS ; Return from subroutine
;----------DVGA Blank Screen ---------------------
;-- Parameters - VOID
;-------------------------------------------------
DVGA_BLANKSCREEN:
LDA #<VRAM ; Load Low Byte of VRAM address
STA $40 ; Store it in Zero Page 40
LDY #$B0 ; Last page + 1 only partially filled
LDA #$00 ; Set Accu To 0 (fill byte)
LDX #>VRAM+4 ; Init X to last VRAM page number
.loop_outer:
STX $41 ; Store it in Zero Page 41
.loop_inner:
DEY ; (filling high to low is more efficient)
STA ($40),Y ; Store the fill byte
BNE .loop_inner ; ... down to the bottom of the page
DEX ; Prepare to fill next-lower page
CPX #>VRAM ; Is X < VRAM_H?
BCS .loop_outer ; No: fill the next page
LDA #<VRAM ; Set Cursor Location to 0
STA CURSOR_LOC ; Store it into Cursor Location
LDA #>VRAM
STA CURSOR_LOC+1
RTS ; Return from Subroutine
;---------DVGA-Put-String--------------------------
;-- Parameters - ZP10 - Ptr to String to Put on Scr
;-- Desc: Puts String on Screen at Cursor Location
;--------------------------------------------------
DVGA_PUTS:
TYA ; Save Y
PHA ; Push Y on stack
TXA ; Save X
PHA ; Push X on Stack
LDY #$00 ; Set Y To Zero
.loop
LDA ($10),Y ; Load Byte of String
BEQ .stringDone ; If this is a NULL character We are done with string
STA (CURSOR_LOC) ; Store this character into Cursor Location
INC CURSOR_LOC ; Increase Cursor Location
BMI .increaseCursorH
LDA CURSOR_LOC
CMP #$B0
BEQ .checkCursor ; Check to see if we are at 1200
.continueLoop
INY ; Increase Y
BMI .stringDone ; Y Overflowed to 00 - String is over 256 Characers, Exit
JMP .loop
.increaseCursorH
INC CURSOR_LOC+1
JMP .continueLoop
.checkCursor
LDA CURSOR_LOC+1
CMP #$84
BNE .continueLoop
LDA #$80
STA CURSOR_LOC+1
LDA #$00
STA CURSOR_LOC
JMP .loop
.stringDone
PLA ; Grab X From Stack
TAX ; Restore X
PLA ; Grab Y from Stack
TAY ; Restore Y
RTS
;--------------------------------------------------
;---------Static STRINGS---------------------------
;--------------------------------------------------
S_HelloWorld: .db "Hello World!", $00
;--------------------------------------------------
;---------BUILT IN ROM CHARS-----------------------
;--------------------------------------------------
CHAR_ROM: ; ASCII encoded - 128 Chars
.BYTE @00000000
.BYTE @00000000
.BYTE @00000000
.BYTE @00000000
.BYTE @00000000
.BYTE @00000000
.BYTE @00000000
.BYTE @00000000
.BYTE @00000000
.BYTE @00111110
.BYTE @01000001
.BYTE @01010101
.BYTE @01000001
.BYTE @01010101
.BYTE @01001001
.BYTE @00111110
.BYTE @00000000
.BYTE @00111110
.BYTE @01111111
.BYTE @01101011
.BYTE @01111111
.BYTE @01101011
.BYTE @01110111
.BYTE @00111110
.BYTE @00000000
.BYTE @00100010
.BYTE @01110111
.BYTE @01111111
.BYTE @01111111
.BYTE @00111110
.BYTE @00011100
.BYTE @00001000
.BYTE @00000000
.BYTE @00001000
.BYTE @00011100
.BYTE @00111110
.BYTE @01111111
.BYTE @00111110
.BYTE @00011100
.BYTE @00001000
.BYTE @00000000
.BYTE @00001000
.BYTE @00011100
.BYTE @00101010
.BYTE @01111111
.BYTE @00101010
.BYTE @00001000
.BYTE @00011100
.BYTE @00000000
.BYTE @00001000
.BYTE @00011100
.BYTE @00111110
.BYTE @01111111
.BYTE @00111110
.BYTE @00001000
.BYTE @00011100
.BYTE @00000000
.BYTE @00000000
.BYTE @00011100
.BYTE @00111110
.BYTE @00111110
.BYTE @00111110
.BYTE @00011100
.BYTE @00000000
.BYTE @11111111
.BYTE @11111111
.BYTE @11100011
.BYTE @11000001
.BYTE @11000001
.BYTE @11000001
.BYTE @11100011
.BYTE @11111111
.BYTE @00000000
.BYTE @00000000
.BYTE @00011100
.BYTE @00100010
.BYTE @00100010
.BYTE @00100010
.BYTE @00011100
.BYTE @00000000
; I removed the rest of the Characters to shorten post - you get the idea
;---------VECTORS----------------------------------
VECTORS:
.ORG $FFFA ; 6502 Starts reading its vectors here
.word HALT ; NMI
.word RESET ; RESET
.word HALT ; BRK
.END