6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue May 14, 2024 11:01 pm

All times are UTC




Post new topic Reply to topic  [ 34 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 11:03 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
I just managed to squeeze in the INC/DEC A instructions. The ALU already had the muxes to get 'A' on the AI input and +1/-1 on the BI input. The problem was that there was no control option to get both at the same time.

But then I just realized that I could also switch the inputs around, and put 'A' on the BI input which still had one unused mux input, and then use the carry input to switch between +1/-1. Changes to the ALU took 24 extra product terms, but no extra macrocell:
Code:
Function    Mcells      FB Inps     Pterms      IO
Block       Used/Tot    Used/Tot    Used/Tot    Used/Tot
FB1          18/18*      52/54       74/90       8/ 9
FB2          17/18       44/54       87/90       9/ 9*
FB3          18/18*      43/54       71/90       9/ 9*
FB4          18/18*      31/54       43/90       7/ 7*
             -----       -----       -----      -----
             71/72      170/216     275/360     33/34

Control logic only needed 3 extra product terms:
Code:
Function    Mcells      FB Inps     Pterms      IO
Block       Used/Tot    Used/Tot    Used/Tot    Used/Tot
FB1          16/18       29/54       68/90       9/ 9*
FB2          14/18       46/54       81/90       9/ 9*
FB3          11/18       23/54       87/90       8/ 9
FB4          12/18       20/54       83/90       7/ 7*
             -----       -----       -----      -----
             53/72      118/216     319/360     33/34


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 11:04 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10800
Location: England
Remarkable! Please do say a little about how you've removed so many dead cycles - do you do some predecode during the fetch cycle perhaps?


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 11:25 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
All I do in the fetch cycle is finish the previous operation, and register the DB input in the IR. The core then moves to the decode cycle, where IR is examined. I've tried to give maximum access time for external memories, so AB/WE outputs are all registered, and DB input is registered as much as possible (only exception is ZP,X where DB+X is loaded in ABL). Quite a lot is happening in the decode state, though. It sets up all the control signals for ABL/ABH/ALU to start working right away.

A large part of dead cycle removal is due to the fact that the address arithmetic is all done locally in the ABL/ABH modules, rather than in the ALU. I think this may be a worthwhile approach for my FPGA core as well. I suspect that it will end up smaller. The extra adder is almost free (esp on LUT6), and you save a lot on muxes, which are expensive.

Code:
0400  A2 00                ldx #0
0402  E8                   inx
0403  E8                   inx
0404  E8                   inx
0405  20 13 04             jsr sub
0408  A1 12                lda ($12,x)
040A  B5 12                lda $12,x
040C  4C 0C 04             jmp loop
0413  60                   rts

Here's an example of the debug output
Code:
          0  FETCH AB:0400 [16] DB:a2 PC:0401 IR:00 1 SEL:1+0 OP:0 DST:0 DL:00 BI:ff ALU:00 WE:1 AHL:00 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1

LDX #00   1 DECODE AB:0401 [16] DB:00 PC:0402 IR:a2 0 SEL:4+0 OP:0 DST:0 DL:a2 BI:5d ALU:00 WE:1 AHL:a2 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
          2  FETCH AB:0402 [16] DB:e8 PC:0403 IR:a2 1 SEL:1+0 OP:0 DST:2 DL:00 BI:ff ALU:00 WE:1 AHL:00 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

INX       3 DECODE AB:0403 [16] DB:e8 PC:0404 IR:e8 1 SEL:5+1 OP:6 DST:2 DL:e8 BI:00 ALU:01 WE:1 AHL:e8 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 001010 (1) IRQ:1 RDY:1

INX       4 DECODE AB:0404 [16] DB:e8 PC:0405 IR:e8 1 SEL:5+1 OP:6 DST:2 DL:e8 BI:00 ALU:02 WE:1 AHL:e8 SB:01 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

INX       5 DECODE AB:0405 [16] DB:20 PC:0406 IR:e8 1 SEL:5+1 OP:6 DST:2 DL:e8 BI:00 ALU:03 WE:1 AHL:e8 SB:02 S:ff A:00 X:02 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

JSR       6 DECODE AB:0406 [26] DB:13 PC:0407 IR:20 0 SEL:4+0 OP:3 DST:0 DL:20 BI:df ALU:03 WE:1 AHL:20 SB:03 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
          7   STK0 AB:01ff [27] DB:04 PC:0407 IR:20 0 SEL:2+0 OP:3 DST:0 DL:13 BI:ec ALU:00 WE:0 AHL:13 SB:00 S:fe A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
          8   STK1 AB:01fe [18] DB:07 PC:0407 IR:20 0 SEL:0+0 OP:3 DST:0 DL:04 BI:00 ALU:00 WE:0 AHL:13 SB:00 S:fd A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
          9   ABS0 AB:0407 [ 7] DB:04 PC:0408 IR:20 0 SEL:0+0 OP:3 DST:0 DL:07 BI:00 ALU:00 WE:1 AHL:13 SB:00 S:fd A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         10  FETCH AB:0413 [16] DB:60 PC:0414 IR:20 1 SEL:1+0 OP:3 DST:0 DL:04 BI:ff ALU:04 WE:1 AHL:13 SB:04 S:fd A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

RTS      11 DECODE AB:0414 [25] DB:68 PC:0414 IR:60 0 SEL:4+0 OP:0 DST:0 DL:60 BI:9f ALU:03 WE:1 AHL:60 SB:03 S:fd A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         12   STK0 AB:01fe [28] DB:07 PC:0414 IR:60 0 SEL:2+0 OP:0 DST:0 DL:68 BI:97 ALU:00 WE:1 AHL:60 SB:00 S:fe A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         13   STK1 AB:01ff [ 0] DB:04 PC:0414 IR:60 0 SEL:0+0 OP:0 DST:0 DL:07 BI:00 ALU:00 WE:1 AHL:07 SB:00 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         14  FETCH AB:0408 [16] DB:a1 PC:0409 IR:60 1 SEL:1+0 OP:0 DST:0 DL:04 BI:ff ALU:04 WE:1 AHL:07 SB:04 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

LDA ($12,X) DECODE AB:0409 [ 8] DB:12 PC:040a IR:a1 0 SEL:4+0 OP:0 DST:0 DL:a1 BI:5e ALU:03 WE:1 AHL:a1 SB:03 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         16  INDX0 AB:0015 [ 1] DB:00 PC:040a IR:a1 0 SEL:4+0 OP:0 DST:0 DL:12 BI:ed ALU:03 WE:1 AHL:12 SB:03 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         17   ABS0 AB:0016 [ 3] DB:00 PC:040a IR:a1 0 SEL:0+0 OP:0 DST:0 DL:00 BI:00 ALU:00 WE:1 AHL:00 SB:00 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         18   DATA AB:0000 [19] DB:00 PC:040a IR:a1 0 SEL:1+0 OP:0 DST:0 DL:00 BI:ff ALU:00 WE:1 AHL:00 SB:00 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         19  FETCH AB:040a [16] DB:b5 PC:040b IR:a1 1 SEL:1+0 OP:0 DST:1 DL:00 BI:ff ALU:00 WE:1 AHL:00 SB:00 S:ff A:00 X:03 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

LDA $12,X   DECODE AB:040b [ 8] DB:12 PC:040c IR:b5 0 SEL:4+0 OP:0 DST:0 DL:b5 BI:4a ALU:03 WE:1 AHL:b5 SB:03 S:ff A:00 X:03 Y:00 CNZDIV: 001010 (0) IRQ:1 RDY:1
         21   DATA AB:0015 [19] DB:00 PC:040c IR:b5 0 SEL:1+0 OP:0 DST:0 DL:12 BI:ff ALU:12 WE:1 AHL:12 SB:12 S:ff A:00 X:03 Y:00 CNZDIV: 001010 (0) IRQ:1 RDY:1
         22  FETCH AB:040c [16] DB:4c PC:040d IR:b5 1 SEL:1+0 OP:0 DST:1 DL:00 BI:ff ALU:00 WE:1 AHL:00 SB:00 S:ff A:00 X:03 Y:00 CNZDIV: 001010 (0) IRQ:1 RDY:1


(AB: address bus, DB: data bus, SEL/OP: alu controls, SB/BI: alu inputs, SB also goes to ABL for address index, ALU: output, AHL: address hold, holds LSB in JSR for example)

Unlike in my other core, ALU output is not registered itself, but goes directly to A,X,Y or DB. Also, memory is asynchronous, so DB shows current value at given address.


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 12:18 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Also added the JMP(ABS,X) instruction. Only took one extra product term in control logic. Oops found a bug, fix raised product terms to 327/360.

Not sure if there's room for the (ZP) instructions. They require extra logic in several places.


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 3:44 pm 
Offline
User avatar

Joined: Sun Oct 18, 2015 11:02 pm
Posts: 428
Location: Toronto, ON
Thanks for sharing that debug output Arlet!

There does seem to be a lot going on in DECODE. For the indexed loads, DECODE seems to decode the opcode, fetch the operand byte and add the index to it, all in one cycle. Is that right? You did mention above that DECODE sets up the address for the memory read and the ALU operation inputs as well, but I’m not sure I’m reading this correctly.

_________________
C74-6502 Website: https://c74project.com


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 4:18 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Take the LDA ($12,X) instruction for instance.
  • FETCH (of previous instruction): load DB ($A1) into IR .
  • DECODE: DB contains ZP address. CTL examines IR, sends signal to ALU to put X on SB, and sends signal to ABL/ABH to load DB+SB+0 into AB, and to load DB into AHL.
  • INDX0: AB contains ZP+X, DB contains LSB of address. CTL still sends ALU signal to put X on SB, and tells ABL/ABH to load AHL+SB+1 into AB, and to load DB into AHL.
  • ABS0: AB contains ZP+X+1, DB contains MSB. CTL sends ABL/ABH to load DB:AHL+SB into AB.
  • DATA: required data is in DB. Data is copied from DB to DL register in ALU.
  • FETCH: CTL tells ALU to load M into A.

Here's a slightly different example, LDX#5 followed by ADC ($0D,X) where $12 contains $07 and $13 contains $EE, and $EE07 contains $03.

Code:
  FETCH AB:0409 [16] DB:61 PC:040a IR:a2 1 SEL:1+0 OP:0 DST:2 DL:05 BI:ff ALU:05 WE:1 AHL:05 SB:05 S:ff A:30 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
 DECODE AB:040a [ 8] DB:0d PC:040b IR:61 0 SEL:4+0 OP:6 DST:0 DL:61 BI:9e ALU:a3 WE:1 AHL:61 SB:05 S:ff A:30 X:05 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  INDX0 AB:0012 [ 1] DB:07 PC:040b IR:61 0 SEL:4+0 OP:6 DST:0 DL:0d BI:f2 ALU:f7 WE:1 AHL:0d SB:05 S:ff A:30 X:05 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
   ABS0 AB:0013 [ 3] DB:ee PC:040b IR:61 0 SEL:0+0 OP:6 DST:0 DL:07 BI:30 ALU:30 WE:1 AHL:07 SB:00 S:ff A:30 X:05 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
   DATA AB:ee07 [19] DB:03 PC:040b IR:61 0 SEL:3+0 OP:6 DST:0 DL:ee BI:ee ALU:1e WE:1 AHL:07 SB:30 S:ff A:30 X:05 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  FETCH AB:040b [16] DB:20 PC:040c IR:61 1 SEL:3+0 OP:6 DST:1 DL:03 BI:03 ALU:33 WE:1 AHL:03 SB:30 S:ff A:30 X:05 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
 DECODE AB:040c [26] DB:0f PC:040d IR:20 0 SEL:4+0 OP:3 DST:0 DL:20 BI:df ALU:05 WE:1 AHL:20 SB:05 S:ff A:33 X:05 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

In the 2nd FETCH state, the ADC is performed. SEL:3 means A/DL form input pair (input values of ALU are visible in SB and BI), and OP:6 means ADC, DST:1 means load result in A. You can see A register take new value in DECODE of next instruction.

Compare with ADC ($12),Y. The states are exactly the same, except the SB values are different, using 00 during first two cycles, and value of Y for the final address.
Code:
 FETCH AB:0409 [16] DB:71 PC:040a IR:a0 1 SEL:1+0 OP:0 DST:3 DL:03 BI:ff ALU:03 WE:1 AHL:03 SB:03 S:ff A:30 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
DECODE AB:040a [ 8] DB:12 PC:040b IR:71 0 SEL:0+0 OP:6 DST:0 DL:71 BI:30 ALU:30 WE:1 AHL:71 SB:00 S:ff A:30 X:00 Y:03 CNZDIV: 000010 (0) IRQ:1 RDY:1
 INDX0 AB:0012 [ 1] DB:07 PC:040b IR:71 0 SEL:0+0 OP:6 DST:0 DL:12 BI:30 ALU:30 WE:1 AHL:12 SB:00 S:ff A:30 X:00 Y:03 CNZDIV: 000010 (0) IRQ:1 RDY:1
  ABS0 AB:0013 [ 3] DB:ee PC:040b IR:71 0 SEL:6+0 OP:6 DST:0 DL:07 BI:f8 ALU:fb WE:1 AHL:07 SB:03 S:ff A:30 X:00 Y:03 CNZDIV: 000010 (0) IRQ:1 RDY:1
  DATA AB:ee0a [19] DB:03 PC:040b IR:71 0 SEL:3+0 OP:6 DST:0 DL:ee BI:ee ALU:1e WE:1 AHL:07 SB:30 S:ff A:30 X:00 Y:03 CNZDIV: 000010 (0) IRQ:1 RDY:1
 FETCH AB:040b [16] DB:20 PC:040c IR:71 1 SEL:3+0 OP:6 DST:1 DL:03 BI:03 ALU:33 WE:1 AHL:03 SB:30 S:ff A:30 X:00 Y:03 CNZDIV: 000010 (0) IRQ:1 RDY:1
DECODE AB:040c [26] DB:0f PC:040d IR:20 0 SEL:4+0 OP:3 DST:0 DL:20 BI:df ALU:00 WE:1 AHL:20 SB:00 S:ff A:33 X:00 Y:03 CNZDIV: 000010 (0) IRQ:1 RDY:1


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 8:18 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
I have to confess that I only take a glimpse on your verilog files .. that is why I choose the simple way and ask: :roll:

How (if) do you implement interrupts and especially BRK ?


Regards,
Arne

and by the way: Happy New Year to everyone here !


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Tue Jan 01, 2019 10:46 pm 
Offline
User avatar

Joined: Sun Oct 18, 2015 11:02 pm
Posts: 428
Location: Toronto, ON
Very cool to see the interaction between the different CPLDs in your examples, and the cycle-by-cycle explanation is very helpful. Thanks for posting that.

_________________
C74-6502 Website: https://c74project.com


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Wed Jan 02, 2019 4:43 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Here's a BRK. I have 3 stack states, STK0, STK1 and STK2 that handle all stack accesses. The IR determines what happens in each of them, so in STK2 when everything has been pushed, CTL looks at IR and goes to IND0 because it's doing a BRK. Note how the PC helps to maintain track of the vector address. Really, it's just pretending it's loading a JMP($FFFE) at that point. The ABS0 state is the same as for LDA ABS, but it's also loaded in PC, and then goes to FETCH.
Code:
DECODE AB:0402 [26] DB:ea PC:0403 IR:00 0 SEL:4+0 OP:0 DST:0 DL:00 BI:ff ALU:01 WE:1 AHL:00 SB:01 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  STK0 AB:01ff [27] DB:04 PC:0403 IR:00 0 SEL:2+0 OP:0 DST:0 DL:ea BI:15 ALU:00 WE:0 AHL:ea SB:00 S:fe A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  STK1 AB:01fe [29] DB:03 PC:0403 IR:00 0 SEL:0+0 OP:0 DST:0 DL:04 BI:00 ALU:00 WE:0 AHL:ea SB:00 S:fd A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  STK2 AB:01fd [11] DB:34 PC:0403 IR:00 0 SEL:0+0 OP:0 DST:0 DL:03 BI:00 ALU:00 WE:0 AHL:ea SB:00 S:fc A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  IND0 AB:fffe [21] DB:50 PC:ffff IR:00 0 SEL:0+0 OP:0 DST:0 DL:34 BI:00 ALU:00 WE:1 AHL:ea SB:00 S:fc A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  ABS0 AB:ffff [ 7] DB:05 PC:ff00 IR:00 0 SEL:0+0 OP:0 DST:0 DL:50 BI:00 ALU:00 WE:1 AHL:50 SB:00 S:fc A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
 FETCH AB:0550 [16] DB:40 PC:0551 IR:00 1 SEL:1+0 OP:0 DST:0 DL:05 BI:ff ALU:05 WE:1 AHL:50 SB:05 S:fc A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1

An RTI
Code:
DECODE AB:0551 [25] DB:20 PC:0551 IR:40 0 SEL:4+0 OP:0 DST:0 DL:40 BI:bf ALU:01 WE:1 AHL:40 SB:01 S:fc A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  STK0 AB:01fd [28] DB:34 PC:0551 IR:40 0 SEL:2+0 OP:0 DST:0 DL:20 BI:df ALU:00 WE:1 AHL:40 SB:00 S:fd A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  STK1 AB:01fe [28] DB:03 PC:0551 IR:40 0 SEL:0+0 OP:0 DST:0 DL:34 BI:00 ALU:00 WE:1 AHL:34 SB:00 S:fe A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  STK2 AB:01ff [ 7] DB:04 PC:0500 IR:40 0 SEL:0+0 OP:0 DST:0 DL:03 BI:00 ALU:00 WE:1 AHL:03 SB:00 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
 FETCH AB:0403 [16] DB:4c PC:0404 IR:40 1 SEL:1+0 OP:0 DST:0 DL:04 BI:ff ALU:04 WE:1 AHL:03 SB:04 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1

And JMPing in a loop, uses same ABS0 state as before.
Code:
DECODE AB:0404 [16] DB:03 PC:0405 IR:4c 0 SEL:0+0 OP:0 DST:0 DL:4c BI:00 ALU:00 WE:1 AHL:4c SB:00 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  ABS0 AB:0405 [ 7] DB:04 PC:0406 IR:4c 0 SEL:0+0 OP:0 DST:0 DL:03 BI:00 ALU:00 WE:1 AHL:03 SB:00 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
 FETCH AB:0403 [16] DB:4c PC:0404 IR:4c 1 SEL:1+0 OP:0 DST:0 DL:04 BI:ff ALU:04 WE:1 AHL:03 SB:04 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1

DECODE AB:0404 [16] DB:03 PC:0405 IR:4c 0 SEL:0+0 OP:0 DST:0 DL:4c BI:00 ALU:00 WE:1 AHL:4c SB:00 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
  ABS0 AB:0405 [ 7] DB:04 PC:0406 IR:4c 0 SEL:0+0 OP:0 DST:0 DL:03 BI:00 ALU:00 WE:1 AHL:03 SB:00 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
 FETCH AB:0403 [16] DB:4c PC:0404 IR:4c 1 SEL:1+0 OP:0 DST:0 DL:04 BI:ff ALU:04 WE:1 AHL:03 SB:04 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1


Last edited by Arlet on Wed Jan 02, 2019 5:39 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Wed Jan 02, 2019 4:49 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
INC $1234, uses same ABS0, but is followed by DATA state. The CTL module has a 'rmw' (read-modify-write) flip-flop that gets set in the DECODE state, and then ensures that the state machine stays in DATA for extra cycle, while clearing the 'rmw' bit. The ABL/ABH modules just hold current address. In 1st DATA state, the ALU registers DB -> DL, and in 2nd DATA state, it performs the +1, and puts the result on DB, while the CTL module pulls WE down.
Code:
DECODE AB:0401 [16] DB:34 PC:0402 IR:ee 0 SEL:0+1 OP:6 DST:0 DL:ee BI:00 ALU:01 WE:1 AHL:ee SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  ABS0 AB:0402 [ 6] DB:12 PC:0403 IR:ee 0 SEL:0+1 OP:6 DST:0 DL:34 BI:00 ALU:01 WE:1 AHL:34 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  DATA AB:1234 [ 5] DB:00 PC:0403 IR:ee 0 SEL:1+1 OP:6 DST:0 DL:12 BI:00 ALU:13 WE:1 AHL:34 SB:12 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  DATA AB:1234 [19] DB:01 PC:0403 IR:ee 0 SEL:1+1 OP:6 DST:4 DL:00 BI:00 ALU:01 WE:0 AHL:34 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
 FETCH AB:0403 [16] DB:ee PC:0404 IR:ee 1 SEL:1+1 OP:6 DST:0 DL:01 BI:00 ALU:02 WE:1 AHL:01 SB:01 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Wed Jan 02, 2019 4:53 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Here's a JMP($13FC) containing $0400 address (back to itself)
Code:
DECODE AB:0401 [16] DB:fc PC:0402 IR:6c 0 SEL:0+0 OP:0 DST:0 DL:6c BI:00 ALU:00 WE:1 AHL:6c SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  ABS0 AB:0402 [ 7] DB:13 PC:0403 IR:6c 0 SEL:0+0 OP:0 DST:0 DL:fc BI:00 ALU:00 WE:1 AHL:fc SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  IND0 AB:13fc [21] DB:00 PC:13fd IR:6c 0 SEL:0+0 OP:0 DST:0 DL:13 BI:00 ALU:00 WE:1 AHL:fc SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
  ABS0 AB:13fd [ 7] DB:04 PC:13fe IR:6c 0 SEL:0+0 OP:0 DST:0 DL:00 BI:00 ALU:00 WE:1 AHL:00 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
 FETCH AB:0400 [16] DB:6c PC:0401 IR:6c 1 SEL:1+0 OP:0 DST:0 DL:04 BI:ff ALU:04 WE:1 AHL:00 SB:04 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1

CTL goes to same ABS0 state to form the address, but also sets 'ind' flip-flop to indicate there's an indirection, and it needs to follow up with IND0 state. In the IND0 state, it goes back to ABS0, but now with 'ind' cleared.


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Wed Jan 02, 2019 5:37 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Branches use a nice trick. Here's LDX#2, followed DEX, BNE in a loop. The CTL module decides in the DECODE state of the BNE whether to take the branch or not. The (1) after the flags indicates condition is true. When taking the branch, it goes from DECODE->BRA0->FETCH. When not taking the branch, it goes straight to FETCH, ignoring the operand. In the DECODE state, the ALU already takes the operand (DB:fd) and stores it in DL (it does that no matter what), and in the BRA0 state, the ALU then outputs this value on SB. In the ABL/ABH modules, AB is set to PC + SB. This trick helps to keep the address logic simple, because the offset for any address calculation is always taken from SB, avoiding a MUX, which would have required 8 additional macrocells.
Code:
LDX #2  DECODE AB:0401 [16] DB:02 PC:0402 IR:a2 0 SEL:4+0 OP:0 DST:0 DL:a2 BI:5d ALU:00 WE:1 AHL:a2 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
         FETCH AB:0402 [16] DB:ca PC:0403 IR:a2 1 SEL:1+0 OP:0 DST:2 DL:02 BI:ff ALU:02 WE:1 AHL:02 SB:02 S:ff A:00 X:00 Y:00 CNZDIV: 000010 (0) IRQ:1 RDY:1
DEX     DECODE AB:0403 [16] DB:d0 PC:0404 IR:ca 1 SEL:5+0 OP:6 DST:2 DL:ca BI:ff ALU:01 WE:1 AHL:ca SB:02 S:ff A:00 X:02 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
BNE     DECODE AB:0404 [16] DB:fd PC:0405 IR:d0 0 SEL:0+1 OP:6 DST:0 DL:d0 BI:00 ALU:01 WE:1 AHL:d0 SB:00 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
          BRA0 AB:0405 [22] DB:4c PC:0405 IR:d0 0 SEL:1+1 OP:6 DST:0 DL:fd BI:00 ALU:fe WE:1 AHL:fd SB:fd S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
         FETCH AB:0402 [16] DB:ca PC:0403 IR:d0 1 SEL:6+1 OP:6 DST:0 DL:4c BI:b3 ALU:b4 WE:1 AHL:fd SB:00 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
DEX     DECODE AB:0403 [16] DB:d0 PC:0404 IR:ca 1 SEL:5+0 OP:6 DST:2 DL:ca BI:ff ALU:00 WE:1 AHL:ca SB:01 S:ff A:00 X:01 Y:00 CNZDIV: 000010 (1) IRQ:1 RDY:1
BNE     DECODE AB:0404 [16] DB:fd PC:0405 IR:d0 0 SEL:0+1 OP:6 DST:0 DL:d0 BI:00 ALU:01 WE:1 AHL:d0 SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 001010 (0) IRQ:1 RDY:1
         FETCH AB:0405 [16] DB:4c PC:0406 IR:d0 1 SEL:6+1 OP:6 DST:0 DL:fd BI:02 ALU:03 WE:1 AHL:fd SB:00 S:ff A:00 X:00 Y:00 CNZDIV: 001010 (0) IRQ:1 RDY:1

Also, for immediate mode in the first LDX, the state machine just goes to the FETCH state, but sets ALU DST:2 to load X register.


Last edited by Arlet on Wed Jan 02, 2019 6:25 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Wed Jan 02, 2019 6:13 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Using these particular CPLDs means the design is heavily constrained by availability of I/O pins. Each CPLD has 34 possible I/O pins available. I started the design with the address generation logic, realizing that ABL needs access to three 8-bit wide buses (ABL, DB, and SB). Those already take up 24 out of the 34 I/O pins, plus a required clock input means that there are only 9 pins left for control inputs and carry out to ABH.

At first, I had a wider control word, but when the address generation was running correctly in simulation, I made a list of all possible kinds of address generation/PC update, and settled on this list and encoding (taken from states.i in the sources), using a 5 bit control word.
Code:
    AB_RTS1   = 5'b00000, // 0
    AB_INDX0  = 5'b00001, // 1
    AB_INDX1  = 5'b00011, // 3
    AB_RMW    = 5'b00101, // 5
    AB_ABS0   = 5'b00110, // 6
    AB_JMP0   = 5'b00111, // 7

    AB_ZPXY   = 5'b01000, // 8
    AB_BRK2   = 5'b01011, // 11
    AB_NMI    = 5'b01101, // 13
    AB_RST    = 5'b01110, // 14

    AB_FETCH  = 5'b10000, // 16
    AB_IRQ0   = 5'b10001, // 17
    AB_JSR1   = 5'b10010, // 18
    AB_DATA   = 5'b10011, // 19
    AB_TXS    = 5'b10100, // 20
    AB_IND0   = 5'b10101, // 21
    AB_BRA0   = 5'b10110, // 22

    AB_PHA    = 5'b11000, // 24
    AB_PLA    = 5'b11001, // 25
    AB_BRK    = 5'b11010, // 26
    AB_JSR0   = 5'b11011, // 27
    AB_RTS0   = 5'b11100, // 28
    AB_BRK1   = 5'b11101; // 29

The names are based on most common usage, but may be used for other cases that require same output. For instance, the AB_PHA is used for PHA, but also for PHP and interrupt handling. The list is divided into 4 groups, based on left two bits.
  • Group 00 : uses AHL as base address. This is a register used to hold earlier address.
  • Group 01 : uses DB as base address, also includes vectors
  • Group 10 : uses PCL as base address
  • Group 11 : uses SPL (stack pointer) as base address
Depending on the rest of the encoding, the SB may be added to this base address, and optionally an extra '1'. This extra '1' is added in a couple of places, such as when pulling data from the stack (AB <= SPL + 1), or when doing a RTS which needs deal with fact that PC on the stack points to byte before instruction, or when fetching 2nd ZP address in (ZP,X) or (ZP),Y

Also depending on the control bits, the AHL is loaded or not, and PC is incremented or not. Funny detail: the AB is calculated first, and then the PC is updated on negative clock edge by taking the AB value and adding 1. Adders are big on CPLDs, but adding 1 is reasonably cheap because you only need wide input ANDs, not ORs.

The stack pointer is also stored in the ABL module, including a dedicated incrementer/decrementer for the stack operations. Incrementing is also reasonably cheap, because the CPLD registers can be configured as toggle flip flops. Each bit is set to toggle when all the lower bits are '1', which then only needs a wide 'AND', requiring only single product term (plus a second product term to detect all zeroes for a decrementer) In addition, it's easy to skip incrementing by ANDing in an extra enable signal. Of course, the downside of using a toggle flip flop is that it becomes a bit tricky to load a new value. Loading a new value requires 2 product terms, because it needs to XOR in the current state. To minimize resources, it's best to avoid mixing loads/increments.

You can see the AB operation indicated (as decimal) in the square brackets after the AB field of the debug output.


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Wed Jan 02, 2019 1:42 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Wow! This is an excellent description of what happens and how you implement things. Thank you very much, Arlet!

If I read this correctly, the BRK description actually starts at PC=$0401 where the CPU picks $00 and $ea @0402. Then PC is incremented one more time but $0403 is not referenced, instead PCH, PCL, and Flags (with B=1 !) are stacked. Seems OK.

If you would change BRK to use an own vector, does this require another state of GROUP 01 or do the various vector addresses "drops" into PCL (PCH always $FF) by looking at the interrupt wires?


Another question: did you implement the JSR - RTS in the same fashion as the 6502 does - I mean saving the "wrong" (-1) return address and then increment that address when RTS is executed? I found this behavior particular strange - and nasty as well as it forbids to use RTI as a shortage for PLP, RTS.


Regards,
Arne


Top
 Profile  
Reply with quote  
 Post subject: Re: CPLD 6502
PostPosted: Wed Jan 02, 2019 2:06 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Quote:
If you would change BRK to use an own vector, does this require another state of GROUP 01

Yes. Alternatively, you could instruct the ALU to put a constant on SB, so it will be added to the vector address, maybe to implement a complete interrupt dispatcher.

GaBuZoMeu wrote:
Another question: did you implement the JSR - RTS in the same fashion as the 6502 does - I mean saving the "wrong" (-1) return address and then increment that address when RTS is executed?

Yes, I did. I wanted the core to be fully compatible with 'normal' 6502 software (i.e. software that doesn't rely on undocumented quirks). I suspect the original 6502 did it this way because it just saves current PC contents during JSR, and at that point it doesn't yet point to next instruction. I think they do the +1 in the RTS by just waiting a cycle for the PC to increment by itself.

There's a bug in the code by the way. As you say, 'B' is set in the pushed flags, but it is also set when doing an IRQ. I still need to fix that.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 34 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: