6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Sep 20, 2024 9:43 pm

All times are UTC




Post new topic Reply to topic  [ 122 posts ]  Go to page Previous  1, 2, 3, 4, 5 ... 9  Next
Author Message
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 3:05 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
This is how I'm going to do the Z flag generation. Using one of the left over OR gates per bit slice.

You may wonder about the propagation delay, but that's no concern because of the ripple carry adder, the ALU outputs will arrive in order, so the OR from 0 through 6 will be waiting at the last input before the ALU7 output arrives.


Attachments:
z-flag.png
z-flag.png [ 2.39 KiB | Viewed 865 times ]
Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 3:46 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Arlet wrote:
For BCD operations, the idea is to store the output of the binary addition in A, and at the same time, store the BCD adjustment in M. An extra cycle follows where A+M is calculated and stored in A again.

I was thinking that the BCD adjustment term was either 0, +6 or -6, which is equal to +10. That's how I've done it before in the FPGA/CPLD verilog code.

Thinking about how to optimize the logic for 3 different bit patterns (0000, 0110 and 1010), I realized I could also use the ALU as a subtractor, by inverting B input and setting carry input flag. That way, I only need 0 or +6 as adjustment digits.

Another optimization is that I no longer split my 8 bit adder in two 4 bit pieces. For instance, suppose you add 16 and 16. If you just add them in binary, you get 2C, and then if you add 6 just to lower nibble you get 22, but the answer is 32. In order to fix that, I had split the adder in two 4 bit pieces, and then generate a carry from lower digit into upper digit whenever the result was bigger than 9. So 16 + 16 would first result in 3C, and then the lower nibble would be adjusted C+6=2, resulting in correct answer of 32.

Producting the decimal carry in the middle of the adder adds some gate delay in the ripple chain, plus some extra chaos in the middle of a regular structure.

More or less by accident I tried it without the decimal carry detection. You get 16+16=2C as temporary result. But then when you add the +6 correction to the lower nibble, and just let the carry propagate normally, you end up with 32. And it also works for subtraction, thanks to the +9+Carry trick above. With the old +10 adjustment, it would not work.

Edit: there is a caveat. The carry out is slightly more complicated, because you can get a carry during first addition or during second. This is easily fixed by just OR-ing the second carry into the carry flag. And you can use the binary carry out for this, which should save a little bit of time.

Modified BCD code passes Klaus Dormann's test suite. The Github code has been updated.


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 4:56 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
I've a feeling this might not work (although it would be nice if it did) ... can you run Bruce's decimal tests in simulation?


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 5:16 pm 
Offline
User avatar

Joined: Sun Oct 18, 2015 11:02 pm
Posts: 428
Location: Toronto, ON
The ALU bit slice looks great, and it really starts to show how simplicity is manifesting in the design. Very nice indeed.

Arlet wrote:
More or less by accident I tried it without the decimal carry detection. You get 16+16=2C as temporary result. But then when you add the +6 correction to the lower nibble, and just let the carry propagate normally, you end up with 32. And it also works for subtraction, thanks to the +9+Carry trick above. With the old +10 adjustment, it would not work.
This makes sense, but you do need to adjust the upper nibble to make 99 + 1 work, correct?

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


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 5:36 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Quote:
can you run Bruce's decimal tests in simulation?

It passes Bruce's decimal tests if I modify the code to only check valid BCD numbers. It fails on invalid ones.

For example, my code calculates 0A + 0F as 20, instead of 10. Personally, I like 20 better. :)

I think I'll accept this small deviation from the original. Unless you know of some useful code that depends on "correct" BCD behavior for invalid numbers.


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 5:41 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Drass wrote:
The ALU bit slice looks great, and it really starts to show how simplicity is manifesting in the design. Very nice indeed.

Thanks. Still a long way to go to squeeze it into a Eurocard format :)

Quote:
This makes sense, but you do need to adjust the upper nibble to make 99 + 1 work, correct?

Correct. Whenever the lower nibble is between 10 and 15, and the upper nibble is 9, then you need to force an adjustment. Here's the code (MSD is most significant digit after binary add, DHC is the digital half carry, which indicates lower nibble >= 10)

Code:
/*
 * DC is the decimal carry. It is set when the upper nibble
 * of the result is larger than 9. We need to incorporate
 * the decimal carry from lower nibble here as well, in case
 * the lower nibble generates a carry after correction, while
 * upper nibble is equal to 9.
 */
wire DC  = (MSD[3:0] + DHC) >= 10;


If you write it out in logic you get: DC = MSD[3] & ( MSD[2] | MSD[1] | (MSD[0] & DHC)), which is simple enough.


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 7:21 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
Not necessarily crucial, but here's what Bruce says:


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 7:40 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
For what it's worth, the example that Bruce gave for the ASCII conversion still works with my method. It starts to give different answers when lower nibbles add up to 25 or more.


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 7:51 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
Hurrah!


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sat Jan 05, 2019 8:43 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Rewrote ALU to use gates at same level as schematic. Full code on github, but here's the core of it. For completeness, the 2 modifier bits for the BI input should also be moved into this module.
Code:
wire [7:0] AND = AI & BI;
wire [7:0] EOR = AI ^ BI;
wire [7:0] ORA = AI | BI;

// ripple carry bits
wire C1 = (ORA[0] & CI) | AND[0];
wire C2 = (ORA[1] & C1) | AND[1];
wire C3 = (ORA[2] & C2) | AND[2];
wire C4 = (ORA[3] & C3) | AND[3];
wire C5 = (ORA[4] & C4) | AND[4];
wire C6 = (ORA[5] & C5) | AND[5];
wire C7 = (ORA[6] & C6) | AND[6];
wire C8 = (ORA[7] & C7) | AND[7];

// adder
wire [7:0] ADC = EOR ^ { C7, C6, C5, C4, C3, C2, C1, CI };

// mux
always @*
    case( op )
        ALU_AI:                         OUT = AI;
        ALU_ADC:                        OUT = ADC;
        ALU_ROL:                        OUT = { AI[6:0], CI };
        ALU_ROR:                        OUT = { CI, AI[7:1] };
        ALU_ORA:                        OUT = ORA;
        ALU_EOR:                        OUT = EOR;
        ALU_AND:                        OUT = AND;
    default:                            OUT = 8'h55;
    endcase


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sun Jan 06, 2019 9:34 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Updated the ALU interface to have M register input 'MI', instead of BI input, and added two signals (mem_bi and inv_bi) to select actual BI input. This is a better reflection of actual ALU module, since the mem_bi/inv_bi signals will be implemented using spare AND/XOR gates in ALU.

The M (memory) register is a registered version of DB input so we have full cycle available for math in ALU.

https://github.com/Arlet/ttl-6502/blob/master/alu.v

I also decided to assign the unused ALU mux input to BI. This is not strictly needed, but it allows some alternative ways of implementing certain operations, which could be useful in minimizing decoding logic later on. If I find a better purpose, I can always change it later.


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sun Jan 06, 2019 9:45 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
Thanks for sharing the evolution of this design - one can learn a lot more from the journey, even second hand, compared to just seeing the destination.


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sun Jan 06, 2019 9:51 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
BigEd wrote:
one can learn a lot more from the journey, even second hand, compared to just seeing the destination.

Yes, one of the goals is to make the project educational, so I'm purposely updating the design in small increments, verifying it still passes the test suite, and then checking in results in Github. The beauty of Github is that you can easily go back to older revisions, compare the changes and recreate the evolution.


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sun Jan 06, 2019 10:35 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Made a small simplification in the BCD adjust logic. Instead of outputting a binary 'half carry' signal, I now output a binary 'half carry/half borrow'. Since the ALU now has a 'inv_bi' signal indicating whether it's doing an add or subtract, I can XOR the C4 bit with inv_bi to create a active high carry or borrow signal. This reduces the logic to pick the proper adjustment value from:
Code:
    if( bcdadd & (HC|DHC) )             ADJL = 6;
    else if( bcdsub & ~HC )             ADJL = 6;
    else                                ADJL = 0;
to
Code:
    if( bcd & (HCB|DHC) )               ADJL = 6;
    else                                ADJL = 0;

It can use one of spare XOR gates in the ALU module. Next step is to use an ALU spare OR gate for the HCB|DHC logic, and do the same thing for the upper nibble.

Since these were free gates anyway, the only real cost for BCD support is the mux in front of the M register that needs to select between DB and {ADJH,ADHL}. This can be done easily with two quad 2:1 muxes, like the SN74CBTLV3257, or in individual AND/OR gates (an OR gate for each '1' in the adjustment term, and an AND for each '0'). Since the binary representation of '6' is 0110, this could be done with a quad AND + quad OR. The disadvantage is that the AND needs an inverted input, so I'll probably use muxes instead. Edit: No, wait, I need to select between 0 and 6 and DB. I can still use the mux, and then use the select pin for DB/ADJ, and then tie inputs 0/3 to ground, and tie 1/2 to the adj_lsd/adj_msd signal.

Edit: done. Instead of all the carry flags, the ALU now outputs two signals which indicate which digit needs adjusting.
Code:
    output adj_lsd,             // if set, lower digit needs BCD adjustment
    output adj_msd              // if set, upper digit needs BCD adjustment


Top
 Profile  
Reply with quote  
 Post subject: Re: Yet another TTL 6502
PostPosted: Sun Jan 06, 2019 12:04 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Added full schematic of ALU lower nibble

I've moved the ADC select to B0 input of the MUX. The ADC is the most frequently used operation, and by setting it to input 0, this hopefully will reduce decoding logic later on. I've also added the logic for BCD adjust output and the first half of the Z flag. Still need to assign the inputs for AI/BI/ROL and ROR, but I'll do that when I figure out the easiest lay out.

(Also need to attach all power/ground pins, and sprinkle some bypass caps)


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 25 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: