Page 1 of 5
A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 7:15 pm
by jgroth
I wanted to build a small, simple 6502 computer with as few components as possible and found Garth Wilson's address decoder in his 6502 primer. My computer has 32k ROM, 16k RAM and a 65C22S for I/O. There is also a 74HCT74 and a TL7705.
If I understand Garth's primer correctly the ROM is selected with A15 goes high (A15 is inverted and OE and CS goes low so ROM is selected).
The RAM is selected when the clock is high A15 is low and A14 is low (address $0000-$3fff).
The VIA is selected when the A15 is low, A14 is high and A13 is high.
R/W is connected to W (pin 27 on the RAM).
Have I got this correct?
I wrote a small program that put PA and PB first high then low then high again with a delay of ca 5 sec in between. The program works in another computer and so does all other ICs but that computer has a modified version of 8Bit address decoder.
In my minimalist computer nothing happens.
Code: Select all
;;;
;; coldstart - initialises all hardware
;; power up and reset procedure.
;;;
coldstart: .block
sei ;Turn off interrupts
cld ;Make sure MPU is in binary mode
ldx #0
l1:
stz 0,x ;zero ZP
dex
bne l1
dex ;effectively ldx #$ff
txs ;Initialise stack register
jsr via_init
cli
;;;
;; test code of CPLD's decoding part.
;; Blink a LED every second connected to PA0 on VIA.
;;;
lda #$ff
sta via1ddra ; set all PA pins to be outputs
sta via1ddrb ; set all PB ping to be outputs
loop:
lda #$ff
sta via1ra
sta via1rb
; bra loop
jsr delay
lda #0
sta via1ra
sta via1rb
jsr delay
bra loop
delay: .proc
ldx #$20
loop1:
jsr one_sec_delay
dex
bne loop1
rts
.pend
one_sec_delay: .proc
phx
phy
ldx #$ff
loop1:
ldy #$ff
loop2:
dey
bne loop2
dex
bne loop1
ply
plx
rts
.pend
Re: A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 7:57 pm
by GARTHWILSON
I see the word "Attachment" there, but it does not seem to be attached.
What do you have the VIA addresses set to in your equates? And what's in subroutine via_init?
BTW, the CMOS processor always comes out of reset with the I flag set and the D flag clear. (I see you're using the CMOS processor. The NMOS won't necessarily come out of reset with D clear, but the CMOS does.) Also, you can omit the LDA #0 in the lda #0, sta via1ra, sta via1rb sequence and replace the STA's with STZ. There's no need to zero-out ZP either. There's nothing wrong with your code there; these are only suggestions for shortening it. Edit: actually there's more that could be done to shorten it, but I'll leave it alone now.
Re: A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 8:23 pm
by BigEd
What kind of diagnostic tools do you have? First thing to check is that the CPU comes out of reset, reads the reset vector, and jumps to the start of your code. You might be able to check this is working just by putting appropriate code in your ROM and checking the frequency of the SYNC output. Or by going into a tight loop and reading off all the high order bits of the address bus.
Re: A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 8:50 pm
by jgroth
I see the word "Attachment" there, but it does not seem to be attached.
There should be a file attached now.
What do you have the VIA addresses set to in your equates? And what's in subroutine via_init?
This piece of code:
Code: Select all
via1base = $6000
;;;via1base = $7fc0
via1rb = via1base+0 ; write output register b, read input register b
via1ra = via1base+1 ; write output register a, read input register a
via1ddrb = via1base+2 ; data direction register b
via1ddra = via1base+3 ; data direction register a
via1t1cl = via1base+4 ; write t1 low-order latches, read t1 low-order counter
via1t1ch = via1base+5 ; t1 high-order counter
via1t1ll = via1base+6 ; t1 low-order latches
via1t1lh = via1base+7 ; t1 high-order latches
via1t2cl = via1base+8 ; write t2 low-order latches, read t2 low-order counter
via1t2ch = via1base+9 ; t2 high-order counter
via1sr = via1base+$a ; shift register
via1acr = via1base+$b ; auxiliary control register
via1pcr = via1base+$c ; peripheral control register
via1ifr = via1base+$d ; interrupt flag register
via1ier = via1base+$e ; interrupt enable register
via1ranh = via1base+$f ; same as reg a except no "handshake"
via1ifrirq = %00000111
via1timer1mask = %00000110
via1timer2mask = %00000101
via_timer2_irq_mask = %00100000
via1_init_table
.byte $00 ; PRB
.byte $00 ; PRA
.byte $00 ; DDRB
.byte $00 ; DDRA
.byte $00 ; T1CL
.byte $00 ; T1CH
.byte $00 ; T1LL
.byte $00 ; T1LH
.byte $00 ; T2CL
.byte $00 ; T2CH
.byte $00 ; SR
.byte $00 ; ACR
.byte $00 ; PCR
.byte $7F ; IFR
.byte $7F ; IER
n_via1_registers=*-via1_init_table-1
via_init: .proc
jsr via1_init
rts
.pend
via1_init: .proc
ldx #n_via1_registers
next:
lda via1_init_table,x
sta via1base,x
dex
bpl next
rts
.pend
BTW, the CMOS processor always comes out of reset with the I flag set and the D flag clear. (I see you're using the CMOS processor. The NMOS won't necessarily come out of reset with D clear, but the CMOS does.) Also, you can omit the LDA #0 in the lda #0, sta via1ra, sta via1rb sequence and replace the STA's with STZ. There's no need to zero-out ZP either. There's nothing wrong with your code there; these are only suggestions for shortening it. Edit: actually there's more that could be done to shorten it, but I'll leave it alone now.
Please do note that this code is just a small part of a bios and monitor I'm writing for another SBC that works just fine with the code above, ie I know the code works and yes it can be optimised but what is the point. It is not code I'm going to keep, it just proves that the RAM/ROM and VIA are being decoded correctly. That other SBC is using 8Bit's (Daryl Ritcher) decoder which uses three 74xx. I thought it would be interesting to build something so minimalist that it only takes one NAND to address decode everything.
Re: A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 8:59 pm
by jgroth
What kind of diagnostic tools do you have? First thing to check is that the CPU comes out of reset, reads the reset vector, and jumps to the start of your code. You might be able to check this is working just by putting appropriate code in your ROM and checking the frequency of the SYNC output. Or by going into a tight loop and reading off all the high order bits of the address bus.
Well, I've got two logic probes and a 4 channel 'scope. But I think I would need a single stepper to do what you are proposing properly I think (I think I saw one in Garth's primer or did I dream that). The code how ever works just fine in another SBC I've built that is using Daryl Ricter's decoder. Only difference is the VIA base is $7FE0 on that computer.
So unless I've have misinterpreted Garth's decoder completely or wired something wrong it should work. Or am I missing something?
The schematic should now be attached to my original message.
Re: A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 9:03 pm
by rwiker
It looks like you have the wrong address for the VIA in your test program: $6000 is three quarters of the way through the RAM address space.
If the VIA is selected by A15*/A14*A13, then this corresponds to the address range $a000-$bfff. In that case, $a000 should be a good choice for the VIA base address.
Re: A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 9:04 pm
by BigEd
Edit: crossed in post. Maybe rwiker has spotted the error.
It's because something might be wrong - and something is wrong - that it could be worth starting with basics, like whether it's acting as a computer and running your code. Could you have shorted or swapped address or data? Could you have an open on your glue logic?
A logic probe and scope should be enough. By setting up tight loops and jumping to them, you can control the frequency of SYNC in the loop. If SYNC has the right frequency, then you succeeded in getting to the loop. You can use the logic probe to check that (almost all) of the address bus is where it should be.
A NOP test is another way to check something about your setup: whether the CPU is clocked and is coming out of reset.
Re: A simple 6502 computer (doesn't work though)
Posted: Thu Jun 20, 2019 9:24 pm
by GARTHWILSON
It looks like you have the wrong address for the VIA in your test program: $6000 is three quarters of the way through the RAM address space.
If the VIA is selected by A15*/A14*A13, then this corresponds to the address range $a000-$bfff. In that case, $a000 should be a good choice for the VIA base address.
The ROM uses all of 8000-FFFF. The RAM uses 0000-3FFF. You can write to it at 4000-7FFF, but you cannot read it back, because A14 keeps its output enable false in that range. It's kind of a sneaky way to get another chip-select input on the RAM, using a 32KB RAM as a 16KB. The way he has it puts the VIA at 6000-7FFF, which is fine. So its 16 addresses will be, in binary, 011xxxxxxxxxXXXX, where the lower-case x's are "don't cares" and the capital ones select the VIA register. That part looks ok.
I know the code works and yes it can be optimised but what is the point.
Even if the code works elsewhere, simplifying is part of troubleshooting, and might expose why it works on one hardware but not another.
Re: A simple 6502 computer (doesn't work though)
Posted: Fri Jun 21, 2019 2:48 pm
by jgroth
Even if the code works elsewhere, simplifying is part of troubleshooting, and might expose why it works on one hardware but not another.
OK, here's an optimised version of the via test program (or at least as well as I can optimise it). The code works well on the other computer (let's call it the ref board). Doesn't work on the minimalist board (I'm going to call it the NAND-board).
Code: Select all
* = $8000
.cpu = "w65c02"
;;; via1 device addresses:
via1base = $6000
; via1base = $7fc0
via1rb = via1base+0 ; write output register b, read input register b
via1ra = via1base+1 ; write output register a, read input register a
via1ddrb = via1base+2 ; data direction register b
via1ddra = via1base+3 ; data direction register a
via1t1cl = via1base+4 ; write t1 low-order latches, read t1 low-order counter
via1t1ch = via1base+5 ; t1 high-order counter
via1t1ll = via1base+6 ; t1 low-order latches
via1t1lh = via1base+7 ; t1 high-order latches
via1t2cl = via1base+8 ; write t2 low-order latches, read t2 low-order counter
via1t2ch = via1base+9 ; t2 high-order counter
via1sr = via1base+$a ; shift register
via1acr = via1base+$b ; auxiliary control register
via1pcr = via1base+$c ; peripheral control register
via1ifr = via1base+$d ; interrupt flag register
via1ier = via1base+$e ; interrupt enable register
via1ranh = via1base+$f ; same as reg a except no "handshake"
via1ifrirq = %00000111
via1timer1mask = %00000110
via1timer2mask = %00000101
via_timer2_irq_mask = %00100000
via1_init_table
.byte $00 ; PRB
.byte $00 ; PRA
.byte $00 ; DDRB
.byte $00 ; DDRA
.byte $00 ; T1CL
.byte $00 ; T1CH
.byte $00 ; T1LL
.byte $00 ; T1LH
.byte $00 ; T2CL
.byte $00 ; T2CH
.byte $00 ; SR
.byte $00 ; ACR
.byte $00 ; PCR
.byte $7F ; IFR
.byte $7F ; IER
n_via1_registers=*-via1_init_table-1
via_init: .proc
ldx #n_via1_registers
next:
lda via1_init_table,x
sta via1base,x
dex
bpl next
rts
.pend
nmi:
irq:
;;;
;; coldstart - initialises all hardware
;; power up and reset procedure.
;;;
coldstart: .block
sei ;Turn off interrupts
ldx #$ff
txs ;Initialise stack register
l2:
jsr via_init ;Initialise via
;;;
;; test code
;; Test code for setting PA and PB off, on, off endlessly
;;;
lda #$ff
sta via1ddra ; set all PA pins to be outputs
sta via1ddrb ; set all PB ping to be outputs
loop:
stz via1ra ; low on all out ports
stz via1rb ; low on all out ports
jsr delay ; wait for a while
dec via1ra ; high on all out ports
dec via1rb ; high on all out ports
jsr delay ; wait for a while
bra loop
.bend
delay: .proc
lda #$20
loop1:
ldx #$ff
loop2:
ldy #$ff
loop3:
dey
bne loop3
dex
bne loop2
dea ; decrease .A with 1
bne loop1
rts
.pend
* = $fffa
.word nmi ;NMI
.word coldstart ;RESET
.word irq ;IRQ
It was also suggested to me that a NOP test might reveal whether the CPU comes out of reset and puts $EA on the databus. The program for that looks like this:
When I measure the data bus pins on the CPU they are indeed $EA (%11101010) so the CPU leaves reset and reads the reset vector in the ROM and starts execute NOP. I'm beginning to wonder whether I've missed something when I connected the RAM. Don't know how to check that other than physically check all connections on the bread board. I know there is nothing wrong with the IC it self because it works just fine in REF board.
Re: A simple 6502 computer (doesn't work though)
Posted: Fri Jun 21, 2019 4:10 pm
by Dr Jefyll
Can you post some photos of the project? Often it's helpful to examine things visually.
( And remember, on this forum you're allowed to attach images with your post. There's no need to use a third-party site such as Imgur.)
-- Jeff
Re: A simple 6502 computer (doesn't work though)
Posted: Fri Jun 21, 2019 5:26 pm
by jgroth
Re: A simple 6502 computer (doesn't work though)
Posted: Fri Jun 21, 2019 5:54 pm
by jgroth
The dream is to get this computer to work.
Re: A simple 6502 computer (doesn't work though)
Posted: Fri Jun 21, 2019 6:20 pm
by drogon
The dream is to get this computer to work.
DSC_0363.JPG
Looks interesting - what is it?
-Gordon
Re: A simple 6502 computer (doesn't work though)
Posted: Fri Jun 21, 2019 7:23 pm
by jgroth
The dream is to get this computer to work.
DSC_0363.JPG
Looks interesting - what is it?
-Gordon
It's a 65C02 based computer with 32k ROM and RAM, an SC28L92 DUART, a Lattice MACH4A5 CPLD and some surrounding logic. A very experimental IDE interface is also there. Half of the implementation of the IDE interface is in the CPLD and the rest on the board (
http://blog.retroleum.co.uk/electronics ... interface/. But since I can't even get a NOP ROM to work I thought it is time to go back to basic hence the bread board computer where the NOP ROM does work BTW. The VIA doesn't want to play ball though (still wonder if it got something to do with the RAM though).
Re: A simple 6502 computer (doesn't work though)
Posted: Fri Jun 21, 2019 8:28 pm
by GARTHWILSON
One step to try might be to pare it down further, if you're comfortable with that. You have a lot there that's not necessary. For example, the data sheet says, "The reset input clears all internal registers to logic 0 (except T1 and T2 latches and counters and the shift register). This places all peripheral interface lines in the input state, disables the timers, shift register, etc. and disables interrupt from the chip." So the only setup you need it to make port B (PB) all outputs, by writing FF to DDRB. Then decrementing PB, regardless of where it started from, will cycle all the bits, bit 7 being slowest, cycling about every 2/3 second at 1MHz, 1/3 second @ 2MHz, etc., plenty easy to see with a flashing LED.
Code: Select all
* = $8000
.cpu = "w65c02"
;;; via1 device addresses:
via1base = $6000
via1rb = via1base+0 ; write output register b, read input register b
via1ddrb = via1base+2 ; data direction register b
nmi:
irq:
;;;
;; coldstart - initialises PB as all outputs.
;; (The rest is taken care of by the RST-low pulse.)
;;;
coldstart: .block
ldx #$ff
txs ; Initialise stack pointer register
stx via1ddrb ; and make PB0-PB7 all outputs.
;;;
;; Test code for toggling PB7 (and other bits too, but faster), endlessly
;;;
loop: dec via1rb ; PB7 will cycle high & low
jsr delay ; at about 2/3 second at 1MHz, PB6 at
bra loop ; twice that rate, PB5 4x that rate, etc..
.bend ; (That's plenty easy to see with an LED.)
delay: .proc
ldx #$ff
loop2: ldy #$ff
loop3: dey
bne loop3
dex
bne loop2
rts
.pend
* = $fffa
.word nmi ;NMI
.word coldstart ;RESET
.word irq ;IRQ
The 65c02 can be single-cycled; so using a single-cycle circuit like what's 3/4 of the way down the
clock-generation page of the 6502 primer, you can stop at each phase-2-high time and probe around looking at logic states and looking for voltages that are not a solid logic high or low, indicating bus contention. (The power supply's current meter might also tell you that when you get to the troublesome cycle.) WDC's W65C02S allows you to stop in either phase of the clock, not just the phase-2-high time; but you will still need to debounce.