Simulation vs Synthesis

S

Simon

Guest
So I have a partly-complete design for a 6502 CPU, it's simulating just fine for the implemented opcodes, but when I run synthesis, I get a whole load of "Sequential element (\newSPData_reg[23] ) is unused and will be removed from module execute.", one for each bit in the register, in fact.

I know the logic is *trying* to use this register, I can see the values in the register changing during simulation runs, but I can't for the life of me see why it would be removed - the 'execute' module is basically a case statement, with one of the cases explicitly setting the value of the 'newSPData' register.

Again, in the simulation, I see the case being executed, and the values changing. I guess what I'm looking for is any tips on how to tackle the problem ("The Knowledge", if you will), I've already tried the 'trace through the logic for the case that should trigger the case in question, and see if anything jumps out at me'. I remain un-jumped-out-at [sigh].

I'm happy to send the design if anyone wants to have a look, but it's a chunk of verilog code, so didn't want to paste it here...

Cheers
Simon.
 
On 11/30/2015 1:27 AM, Simon wrote:
) is unused and will be removed from module execute.", one for each bit in the register, in fact.

I know the logic is *trying* to use this register, I can see the values in the register changing during simulation runs, but I can't for the life of me see why it would be removed - the 'execute' module is basically a case statement, with one of the cases explicitly setting the value of the 'newSPData' register.

Again, in the simulation, I see the case being executed, and the values changing. I guess what I'm looking for is any tips on how to tackle the problem ("The Knowledge", if you will), I've already tried the 'trace through the logic for the case that should trigger the case in question, and see if anything jumps out at me'. I remain un-jumped-out-at [sigh].

I'm happy to send the design if anyone wants to have a look, but it's a chunk of verilog code, so didn't want to paste it here...

Usually logic is removed because the result is not used anywhere. You
can design and simulate a design only to see the synthesizer remove the
entire thing if it has no outputs that make it to an I/O pin.

So where are the outputs of your register used? Do they actually connect?

--

Rick
 
In article <450e997a-afd7-4c3d-a181-b324af6ede3c@googlegroups.com>,
Simon <google@gornall.net> wrote:
So I have a partly-complete design for a 6502 CPU, it's simulating
just fine for the implemented opcodes, but when I run synthesis, I
get a whole load of "Sequential element (\newSPData_reg[23] ) is
unused and will be removed from module execute.", one for each bit
in the register, in fact.

I know the logic is *trying* to use this register, I can see the values
in the register changing during simulation runs, but I can't for the
life of me see why it would be removed - the 'execute' module is
basically a case statement, with one of the cases explicitly setting
the value of the 'newSPData' register.

Again, in the simulation, I see the case being executed, and the
values changing. I guess what I'm looking for is any tips on how to
tackle the problem ("The Knowledge", if you will), I've already
tried the 'trace through the logic for the case that should trigger
the case in question, and see if anything jumps out at me'. I
remain un-jumped-out-at [sigh].
snip

Simon - just ignore the message and move on. Really.
Synthesis optimizations are quite advanced these
days - both combinatorial and across registers.

Some sort of optimization that may not be obvious to
you, may have combined your register bit with another,
leaving this one "unused". It's ok. Trust the tool,
and just move on.

Regards,

Mark
 
Thanks for all the replies, guys :)

On Sunday, November 29, 2015 at 11:51:03 PM UTC-8, rickman wrote:
Usually logic is removed because the result is not used anywhere. You
can design and simulate a design only to see the synthesizer remove the
entire thing if it has no outputs that make it to an I/O pin.

So where are the outputs of your register used? Do they actually connect?

Actually, this may be it. I had tried to counter this by exporting the databus (both input and output) in the top-level test-bench module, but thinking about it, the registers it's removing are from code that exercises the BRK instruction, which only affects the stack-pointer and program-counter, both of which are internal to the CPU in the design as it stands, and the BRK instruction is currently the only thing to manipulate the stack pointer (I'm going alphabetically through the instruction list, and I've only got as far as EOR :)

Sounds like a likely candidate for what the problem is. Presumably once other things start to also reference the stack pointer (eg: PLA - pull accumulator from stack, where A is also linked to the data-bus via other instructions) it will sort itself out.

If this isn't the case, is there any sort of annotation/directive to say "keep this stuff, I need it!" - there used to be something in ISE in the synthesis directives, but I looked last night, and didn't see anything there in Vivado 2015.4...

On Monday, November 30, 2015 at 8:55:51 AM UTC-8, Tim Wescott wrote:
Doesn't the 6502 have a 16-bit or smaller stack pointer? If so, maybe
you've declared it bigger than it should be, and the synthesizer is
trimming it to what's used?

If it were just the bits I know are being unused (the top 8), I'd be fine with that :) The 'execute' module can push up to (currently, using the BRK instruction) 3 bytes of data onto the stack. I had declared a 32-bit exported register in the module to store these (as well as a 2-bit count register to say how many bytes were waiting), and then the cpu core (once 'execute' has had its way) gets to actually manipulate the stack pointer by transferring data from the shared port to the actual stack. The problem was that all 32 bits were being "optimized" away, even though BRK was definitely pushing 3 bytes into it.

On Monday, November 30, 2015 at 10:26:13 AM UTC-8, Mark Curry wrote:
Simon - just ignore the message and move on. Really.
Synthesis optimizations are quite advanced these
days - both combinatorial and across registers.

Some sort of optimization that may not be obvious to
you, may have combined your register bit with another,
leaving this one "unused". It's ok. Trust the tool,
and just move on.

I see - this dovetails into what Rick is saying above - assuming I'm right that things won't be able to be optimized away once all the instructions are present.

I was just concerned that I was doing all this work, and at the end of the day I'd have a "cpu" that didn't do very much :)

Thanks all, again :)

Simon
 
Simon <google@gornall.net> wrote:
Thanks for all the replies, guys :)

On Sunday, November 29, 2015 at 11:51:03 PM UTC-8, rickman wrote:

Usually logic is removed because the result is not used anywhere. You
can design and simulate a design only to see the synthesizer remove the
entire thing if it has no outputs that make it to an I/O pin.

(snip)

Actually, this may be it. I had tried to counter this by exporting
the databus (both input and output) in the top-level test-bench
module, but thinking about it, the registers it's removing are
from code that exercises the BRK instruction, which only affects
the stack-pointer and program-counter, both of which are internal
to the CPU in the design as it stands, and the BRK instruction
is currently the only thing to manipulate the stack pointer
(I'm going alphabetically through the instruction list, and
I've only got as far as EOR :)

(snip)

If this isn't the case, is there any sort of annotation/directive
to say "keep this stuff, I need it!" - there used to be something
in ISE in the synthesis directives, but I looked last night,
and didn't see anything there in Vivado 2015.4...

I believe so, but I haven't tried it.

Sometimes I only want to know if a design will fit into a certain
FPGA, and not actually do anything with it. In that case, I would
not want to optimize things out.

Most often, though, when something goes away, the optimizer is
right and my design is wrong. It only takes a small mistake to
propagate through and remove a lot of logic.

I have had, at least once, all logic removed!

-- glen
 
jt_eaton <84408@fpgarelated> wrote:

(snip)

Back probably before you were born somebody created an optimizing
compiler that gave an incredible benchmark time until they realized
that the benchmark did an huge amount of work to create a result but
then never bothered to use it anywhere.

All the code was optimised away.

There are stories like that, but one I remember is where the code
was not optimized away, but all done at compile time. Well, that
means almost all optimized away.

It was a Fortran benchmark that did complicated calculations
using statement functions. Statement functions in Fortran are
one line functions, used similar to the way #define is used
in C, though at the time it was not usual for them to be expanded
inline.

The IBM OS/360 Fortran H compiler, from the 1960's, did expand them
inline, and also did constant expression evaluation, unlike many
other compilers. The resulting code printed out the constant.

In the case of FPGAs, it might optimize down to a constant output,
with no logic left.

-- glen
 
Mark Curry <gtwrek@sonic.net> wrote:
In article <450e997a-afd7-4c3d-a181-b324af6ede3c@googlegroups.com>,
Simon <google@gornall.net> wrote:
So I have a partly-complete design for a 6502 CPU, it's simulating
just fine for the implemented opcodes, but when I run synthesis, I
get a whole load of "Sequential element (\newSPData_reg[23] ) is
unused and will be removed from module execute.", one for each bit
in the register, in fact.

(snip)

Simon - just ignore the message and move on. Really.
Synthesis optimizations are quite advanced these
days - both combinatorial and across registers.

Since he did the simulation, that is probably what he should do.

Often enough, I test my designs in an FPGA, and optimizing out
means the logic is wrong.

One I remember was video display logic where the logic was wrong
on the video output. Maybe an enable for a tristate output.

The result then recursively eliminates logic from that point back,
which was everthing except the sync generator.

I think the messages are generated in the order that the constant
signals are found, so start with the message that comes first.
It will say that some signal is constant, often a flip-flop
that has a constant output. Find out why.

Some sort of optimization that may not be obvious to
you, may have combined your register bit with another,
leaving this one "unused". It's ok. Trust the tool,
and just move on.

Yes, combined registers are okay.

-- glen
 
On 30/11/2015 06:27, Simon wrote:
) is unused and will be removed from module execute.", one for each bit in the register, in fact.

I know the logic is *trying* to use this register, I can see the values in the register changing during simulation runs, but I can't for the life of me see why it would be removed - the 'execute' module is basically a case statement, with one of the cases explicitly setting the value of the 'newSPData' register.

Again, in the simulation, I see the case being executed, and the values changing. I guess what I'm looking for is any tips on how to tackle the problem ("The Knowledge", if you will), I've already tried the 'trace through the logic for the case that should trigger the case in question, and see if anything jumps out at me'. I remain un-jumped-out-at [sigh].

I'm happy to send the design if anyone wants to have a look, but it's a chunk of verilog code, so didn't want to paste it here...

Cheers
Simon.

Hi Simon,

Before you spend a lot of time analysing the synthesis messages I would
suggest you run a gate level simulation. If that fails then start
looking at the gate level and warning/note messages. Synthesis tools are
quite clever these days and it is not unusual for the synthesis tools to
add/remove or merge registers.

Good luck,

Hans
www.ht-lab.com
 
On Sun, 29 Nov 2015 22:27:00 -0800, Simon wrote:

So I have a partly-complete design for a 6502 CPU, it's simulating just
fine for the implemented opcodes, but when I run synthesis, I get a
whole load of "Sequential element (\newSPData_reg[23] ) is unused and
will be removed from module execute.", one for each bit in the register,
in fact.

I know the logic is *trying* to use this register, I can see the values
in the register changing during simulation runs, but I can't for the
life of me see why it would be removed - the 'execute' module is
basically a case statement, with one of the cases explicitly setting the
value of the 'newSPData' register.

Again, in the simulation, I see the case being executed, and the values
changing. I guess what I'm looking for is any tips on how to tackle the
problem ("The Knowledge", if you will), I've already tried the 'trace
through the logic for the case that should trigger the case in question,
and see if anything jumps out at me'. I remain un-jumped-out-at [sigh].

I'm happy to send the design if anyone wants to have a look, but it's a
chunk of verilog code, so didn't want to paste it here...

Cheers
Simon.

Doesn't the 6502 have a 16-bit or smaller stack pointer? If so, maybe
you've declared it bigger than it should be, and the synthesizer is
trimming it to what's used?

--
www.wescottdesign.com
 
I'm happy to send the design if anyone wants to have a look, but >it's a
chunk of verilog code, so didn't want to paste it here...

Cheers
Simon.

Thats why we have github.com


Back probably before you were born somebody created an optimizing
compiler that gave an incredible benchmark time until they realized
that the benchmark did an huge amount of work to create a result but
then never bothered to use it anywhere.

All the code was optimised away.


John Eaton



--------------------------------------
Posted through http://www.FPGARelated.com
 
On Monday, November 30, 2015 at 1:58:18 PM UTC-8, rickman wrote:
I don't think you are grasping the situation. If the output of the
register isn't connected to anything, you have no need for it, so it is
removed. It does not matter if any other instructions use this
register, if *any* one part of the design uses this register output, it
won't be removed... unless that part of the design is also removed first.

Maybe I'm not. What I was trying to say is that:

- The execute module does write to 'newSPData' during execution of BRK, vis:

newSPData[`NW:0] = pcPlusOne[`ND:`W];
newSPData[`W*2-1:`W] = pcPlusOne[`NW:0];
newSPData[`W*3-1:`W*2] = ps | 8'h10;

- The 'newSPData' register is declared in the execute module's port list

module execute
(
...
output reg [`W*3-1:0] newSPData, // Bytes to stuff onto stack
output reg [1:0] numSPBytes // Number of bytes to stuff onto stack
);

- The 6502 module does link through to these ports:

execute execute_inst
(
...
.newSPData(newSPData),
.numSPBytes(numSPBytes)
);

- The 6502 module does use the 'wire' vars that link through to the execute registers...

...
if ((action & `UPDATE_SP) == `UPDATE_SP)
begin
if (numSPBytes == 1)
begin
stack[SP] <= newSPData[`NW:0];
SP <= SP - 1;
end
else if (numSPBytes == 2)
begin
stack[SP] <= newSPData[`NW:0];
stack[SP-1] <= newSPData[`W*2-1:`W];
SP <= SP - 2;
end
else if (numSPBytes == 3)
begin
stack[SP] <= newSPData[`NW:0];
stack[SP-1] <= newSPData[`W*2-1:`W];
stack[SP-2] <= newSPData[`W*3-1:`W*2];
SP <= SP - 3;
end
end

Now the coding could be a bit more elegant, but its been through several iterations of "perhaps I ought to be more explicit" ... so forgive me that :)

What I was trying (seemingly, failing :) to say is that nothing else uses 'stack' (apart from an initialize block that zeros out the values), therefore it could be optimized away, ergo the newSPData could be optimized away, ergo my warning messages. Nothing else uses 'stack' because there's no other stack-related CPU operations yet, just the BRK instruction which happens to push stuff onto the stack.

I'm also getting advice to "just ignore the message and move on", and it's hard to correlate that with "I think you still need to look at the code and figure out why the registers don't drive any inputs".

If I'm still not grasping it (or not explaining what I'm thinking well enough), the code is at http://0x0000ff.com/6502/ although the formatting leaves a little to be desired.

Cheers, and many thanks to everyone for all the help :)
 
On Monday, November 30, 2015 at 3:44:28 PM UTC-8, BobH wrote:
If nothing is using the stack output, there is a decent chance that it
is getting optimized out, then there is no user for newSP's output and
it will get optimized out. Check and see if the stack registers are
getting optimized out.

So, oddly enough, there's no mention of 'stack' in the synthesis report (CTRL-F doesn't find anything either), even though it's declared (as registers) alongside the zero-page file in an identical fashion:

////////////////////////////////////////////////////////////////////////////
// Set up zero-page as register-based for speed reasons
////////////////////////////////////////////////////////////////////////////
reg [`NW:0] zp[0:255]; // Zero-page

////////////////////////////////////////////////////////////////////////////
// Same for stack
////////////////////////////////////////////////////////////////////////////
reg [`NW:0] stack[0:255]; // Stack-page

'zp' gets a lot of mentions (mainly that it's too sparse to go into blockRAM) but nary a hint of 'stack' anywhere to be seen.

Looking at the summaries, there are 268 8-bit registers declared, which is only sufficient for either 'stack' or 'zp', but not both together (unless it's cherry-picking the used ones from both declarations of course).

Curiouser and curiouser, quoth the raven^W^W^W said Alice...

If you have brought the stack out to a top level output (pin) it should
not get optimized out.

No I haven't, it's self-contained within the '6502' module, but I could try doing that tonight.

A mistake that I have made, is to mis-spell the wire connection and then
there is no user for the outputs. The easiest way to check that is to
inspect the simulation at the inputs to the next stage that uses the
data and make sure that they are wiggling as you expect and not showing
undefined as they would for an undriven wire. The second easiest way to
check that is to eyeball the naming for this problem.

Yep, I've done that too :)
 
Just to follow up, it definitely is because it's being optimised away. If I add a port which links to a byte of the stack register space, and link it to the top-level test bench...

module cpu_6502
(
...
output reg [`NW:0] stackff
);

////////////////////////////////////////////////////////////////////////////
// Set up the stack as a register array
////////////////////////////////////////////////////////////////////////////
reg [`NW:0] stack[0:255]; // Stack-page

always @ (posedge(clk))
stackff <= stack[255];


.... the report tells me that bits [31:8] of 'newSPData' are optimised away, but bits [7:0] are not.

Aside: The report is also saying: "INFO: [Synth 8-5545] ROM "stack_reg[255]" won't be mapped to RAM because address size (32) is larger than maximum supported(25)"

Am I misunderstanding this, or is my declaration wrong ? I'm trying to declare 256 8-bit (`NW is defined to be 7) registers to represent a single page (the 6502 uses page-1 as a stack, so its stack pointer is only 8-bits in size). 256 bytes ought to fit into a 4K-byte block-ram...

Cheers
Simon.
 
On 11/30/2015 2:02 PM, Simon wrote:
Thanks for all the replies, guys :)

On Sunday, November 29, 2015 at 11:51:03 PM UTC-8, rickman wrote:

Usually logic is removed because the result is not used anywhere.
You can design and simulate a design only to see the synthesizer
remove the entire thing if it has no outputs that make it to an I/O
pin.

So where are the outputs of your register used? Do they actually
connect?

Actually, this may be it. I had tried to counter this by exporting
the databus (both input and output) in the top-level test-bench
module, but thinking about it, the registers it's removing are from
code that exercises the BRK instruction, which only affects the
stack-pointer and program-counter, both of which are internal to the
CPU in the design as it stands, and the BRK instruction is currently
the only thing to manipulate the stack pointer (I'm going
alphabetically through the instruction list, and I've only got as far
as EOR :)

Sounds like a likely candidate for what the problem is. Presumably
once other things start to also reference the stack pointer (eg: PLA
- pull accumulator from stack, where A is also linked to the data-bus
via other instructions) it will sort itself out.

I don't think you are grasping the situation. If the output of the
register isn't connected to anything, you have no need for it, so it is
removed. It does not matter if any other instructions use this
register, if *any* one part of the design uses this register output, it
won't be removed... unless that part of the design is also removed first.


If this isn't the case, is there any sort of annotation/directive to
say "keep this stuff, I need it!" - there used to be something in ISE
in the synthesis directives, but I looked last night, and didn't see
anything there in Vivado 2015.4...

If the output of the register isn't being used by the design, why do you
care if it remains? It can't impact any result the hardware can calculate.

I think you still need to look at the code and figure out why the
registers don't drive any inputs.

Rick

--

Rick
 
On 11/30/2015 4:25 PM, Simon wrote:
What I was trying (seemingly, failing :) to say is that nothing else
uses 'stack' (apart from an initialize block that zeros out the values),
therefore it could be optimized away, ergo the newSPData could be optimized
away, ergo my warning messages. Nothing else uses 'stack' because there's no
other stack-related CPU operations yet, just the BRK instruction which
happens to push stuff onto the stack.

If nothing is using the stack output, there is a decent chance that it
is getting optimized out, then there is no user for newSP's output and
it will get optimized out. Check and see if the stack registers are
getting optimized out.

If you have brought the stack out to a top level output (pin) it should
not get optimized out.

A mistake that I have made, is to mis-spell the wire connection and then
there is no user for the outputs. The easiest way to check that is to
inspect the simulation at the inputs to the next stage that uses the
data and make sure that they are wiggling as you expect and not showing
undefined as they would for an undriven wire. The second easiest way to
check that is to eyeball the naming for this problem.

Good Luck,
BobH
 
On 11/30/2015 6:25 PM, Simon wrote:
On Monday, November 30, 2015 at 1:58:18 PM UTC-8, rickman wrote:

I don't think you are grasping the situation. If the output of the
register isn't connected to anything, you have no need for it, so it is
removed. It does not matter if any other instructions use this
register, if *any* one part of the design uses this register output, it
won't be removed... unless that part of the design is also removed first.

Maybe I'm not. What I was trying to say is that:

- The execute module does write to 'newSPData' during execution of BRK, vis:

newSPData[`NW:0] = pcPlusOne[`ND:`W];
newSPData[`W*2-1:`W] = pcPlusOne[`NW:0];
newSPData[`W*3-1:`W*2] = ps | 8'h10;

- The 'newSPData' register is declared in the execute module's port list

module execute
(
...
output reg [`W*3-1:0] newSPData, // Bytes to stuff onto stack
output reg [1:0] numSPBytes // Number of bytes to stuff onto stack
);

- The 6502 module does link through to these ports:

execute execute_inst
(
...
.newSPData(newSPData),
.numSPBytes(numSPBytes)
);

- The 6502 module does use the 'wire' vars that link through to the execute registers...

...
if ((action & `UPDATE_SP) == `UPDATE_SP)
begin
if (numSPBytes == 1)
begin
stack[SP] <= newSPData[`NW:0];
SP <= SP - 1;
end
else if (numSPBytes == 2)
begin
stack[SP] <= newSPData[`NW:0];
stack[SP-1] <= newSPData[`W*2-1:`W];
SP <= SP - 2;
end
else if (numSPBytes == 3)
begin
stack[SP] <= newSPData[`NW:0];
stack[SP-1] <= newSPData[`W*2-1:`W];
stack[SP-2] <= newSPData[`W*3-1:`W*2];
SP <= SP - 3;
end
end

Now the coding could be a bit more elegant, but its been through several iterations of "perhaps I ought to be more explicit" ... so forgive me that :)

What I was trying (seemingly, failing :) to say is that nothing else uses 'stack' (apart from an initialize block that zeros out the values), therefore it could be optimized away, ergo the newSPData could be optimized away, ergo my warning messages. Nothing else uses 'stack' because there's no other stack-related CPU operations yet, just the BRK instruction which happens to push stuff onto the stack.

I'm also getting advice to "just ignore the message and move on", and it's hard to correlate that with "I think you still need to look at the code and figure out why the registers don't drive any inputs".

If I'm still not grasping it (or not explaining what I'm thinking well enough), the code is at http://0x0000ff.com/6502/ although the formatting leaves a little to be desired.

Cheers, and many thanks to everyone for all the help :)

Ok, I think you understand what I am saying. If "stack" is being
optimized away, I would expect to see that also be in the warning
messages. Is it? If not, I can only assume that is not the problem.

I don't know that you need to actually have instructions in your design
that utilize the stack data. As long as there is a data path from
"stack" to other logic and the control signals are driven from logic
that is not optimized away it should remain.

I agree with the others that if you believe this problem is because your
design is not complete, move on. I don't think it will be any harder to
find with a completed design than with a partial design, possibly the
opposite.

I will also say however, that unit testing can be very useful if you
aren't designing it on the fly. If you have decomposed your modules
with full specification of what they do and all the ins and outs, you
should be able to write a test bench for each module.

--

Rick
 
On 11/30/2015 6:44 PM, BobH wrote:
On 11/30/2015 4:25 PM, Simon wrote:
What I was trying (seemingly, failing :) to say is that nothing else
uses 'stack' (apart from an initialize block that zeros out the values),
therefore it could be optimized away, ergo the newSPData could be
optimized
away, ergo my warning messages. Nothing else uses 'stack' because
there's no
other stack-related CPU operations yet, just the BRK instruction which
happens to push stuff onto the stack.

If nothing is using the stack output, there is a decent chance that it
is getting optimized out, then there is no user for newSP's output and
it will get optimized out. Check and see if the stack registers are
getting optimized out.

If you have brought the stack out to a top level output (pin) it should
not get optimized out.

A mistake that I have made, is to mis-spell the wire connection and then
there is no user for the outputs. The easiest way to check that is to
inspect the simulation at the inputs to the next stage that uses the
data and make sure that they are wiggling as you expect and not showing
undefined as they would for an undriven wire. The second easiest way to
check that is to eyeball the naming for this problem.

If you make a spelling error, won't that be flagged because that signal
hasn't been declared?

--

Rick
 
Clearly some explanation required...

I am not clear what you are trying to do with the stack here. Do you
have a relatively complete CPU implemented?

The original design did in fact have a clean simple 64k block of RAM, where no page was special, and yes, it was hung off the address/data buses and life was simple. The timing, however, was not. The original 6502 had a 2-phase clock, in which it could present the address at the beginning of the clock cycle, and the data would be on the data-bus ready for use at the end of the same clock cycle. In this way, instructions that took two memory accesses {read opcode, read argument} could be retired in just 2 clocks.

I don't have that luxury :) I wanted everything to be simple synchronous logic that presented the data on clock N and the result was available at clock N+1. In fact I wanted it even simpler. I wanted to keep the internal logic as simple as possible as well, making everything synced to always @ (posedge(clk)), which means that after a decode operation, it takes 3 clocks to read the data ([abus <= address], [address appears on bus], [data appears on bus]).

The reason for this self-imposed simplicity is that I'm planning on using the design as a test-case for implementing an actual real-life chip - I managed to persuade Cadence to let me use their tools, and I have a 5-week Xmas break coming up (no vacation during the year, so I'm looking forward to it :) I thought an 8-bit processor would be nice and easy, but perhaps I'm aiming too high. Perhaps I ought to look at XOR ...

So, the main challenges are with stack and zero-page instructions because those are the "fast" instructions on a 6502 (2 clocks) that aren't just register->register. I'm already running the CPU internal state at 4x the nominal 'cpu clock' to get the clock-cycle accuracy I need for the instructions that the 6502 took 2 clocks to process, and I'm inserting wait states to sync up the longer (up to 7, so 28 clocks in my world) ones. Once the basic system is in place, I'll allow that to optionally relax, and I can run it in cycle-accurate or "turbo" mode. Perhaps I'll have a "turbo" button (showing my age, here).

My solution to the 2-cycle instructions was to declare 2 pages-worth of registers: page-0, (which is special for the 6502, with special opcodes that take less time to run if they access there) and the stack (which is page-1). The 6502 has an 8-bit stack-pointer, that it always prepends 01h to (to form 16'h01xx), providing a 256-deep stack. The use of a register array for both these pages significantly helps when I only have 2 clocks to play with. Obviously when the CPU wants to store or read values, I need to determine if it's page-0 or page-1 and redirect accordingly, but that's not a high price to pay.

"Relatively complete" is an interesting term. I have a CPU that will execute (at least in simulation [grin]) all the opcodes I have implemented - it does the decode, figures out the addressing mode of the instruction (up to 8 of them), processes the result, and updates the {memory, registers, processor-state-flags, stack} accordingly. The issue is that I've implemented about 1/3 of the opcodes right now... So, the answer is "it depends on what you mean" :)

In Simon's case this may well be due to inputs which are not driven because the instruction decode logic is not implemented. This can
either be causing logic to be optimized because it is constant, or to be optimized because the output is never gated into the next register.
Unless he provides the full code we can't debug this.

The full code is actually available (see link above, or go to http://0x0000ff.com/6502/)

Cheers
Simon.
 
On 11/30/2015 8:53 PM, Tim Wescott wrote:
On Mon, 30 Nov 2015 18:23:43 +0000, Mark Curry wrote:

In article <450e997a-afd7-4c3d-a181-b324af6ede3c@googlegroups.com>,
Simon <google@gornall.net> wrote:
So I have a partly-complete design for a 6502 CPU, it's simulating just
fine for the implemented opcodes, but when I run synthesis, I get a
whole load of "Sequential element (\newSPData_reg[23] ) is unused and
will be removed from module execute.", one for each bit in the register,
in fact.

I know the logic is *trying* to use this register, I can see the values
in the register changing during simulation runs, but I can't for the
life of me see why it would be removed - the 'execute' module is
basically a case statement, with one of the cases explicitly setting the
value of the 'newSPData' register.

Again, in the simulation, I see the case being executed, and the values
changing. I guess what I'm looking for is any tips on how to tackle the
problem ("The Knowledge", if you will), I've already tried the 'trace
through the logic for the case that should trigger the case in question,
and see if anything jumps out at me'. I remain un-jumped-out-at [sigh].
snip

Simon - just ignore the message and move on. Really.
Synthesis optimizations are quite advanced these days - both
combinatorial and across registers.

Some sort of optimization that may not be obvious to you, may have
combined your register bit with another,
leaving this one "unused". It's ok. Trust the tool,
and just move on.

It's been at least five years since I've actually done FPGA work, but I
always took unexpected optimizations of this sort to mean that I didn't
have my head screwed on straight, and I needed to figure out what I was
doing wrong.

Most of the time, I was right.

Yeah, that makes sense. There is a chain of

input --> A --> B --> C --> output

where A, B and C are registered values. Each of them may have many
other internal signals combining to produce the value in the signal and
may be used in other logic internally. If none of the destinations
reach an output or if the inputs are optimized so they do not depend on
anything, but rather are constants (like A and '0' which will always
produce a '0' result) then that logic will be optimized away. This can
remove an entire chain, or perhaps just B and C or any other combination.

In Simon's case this may well be due to inputs which are not driven
because the instruction decode logic is not implemented. This can
either be causing logic to be optimized because it is constant, or to be
optimized because the output is never gated into the next register.
Unless he provides the full code we can't debug this.

I always work from block diagrams which help me to "see" my data flow
which makes it easy to see which control points need to be driven. I
expect Simon's problem is in the instruction decode logic not driving a
signal, but it is hard to tell. The fact that a register is changing
value in the simulator means that it is being given variable values, but
does not mean the output is being used for anything. I'm very unclear
why he has a 32 bit register in an 8 bit processor.

--

Rick
 
On Mon, 30 Nov 2015 18:23:43 +0000, Mark Curry wrote:

In article <450e997a-afd7-4c3d-a181-b324af6ede3c@googlegroups.com>,
Simon <google@gornall.net> wrote:
So I have a partly-complete design for a 6502 CPU, it's simulating just
fine for the implemented opcodes, but when I run synthesis, I get a
whole load of "Sequential element (\newSPData_reg[23] ) is unused and
will be removed from module execute.", one for each bit in the register,
in fact.

I know the logic is *trying* to use this register, I can see the values
in the register changing during simulation runs, but I can't for the
life of me see why it would be removed - the 'execute' module is
basically a case statement, with one of the cases explicitly setting the
value of the 'newSPData' register.

Again, in the simulation, I see the case being executed, and the values
changing. I guess what I'm looking for is any tips on how to tackle the
problem ("The Knowledge", if you will), I've already tried the 'trace
through the logic for the case that should trigger the case in question,
and see if anything jumps out at me'. I remain un-jumped-out-at [sigh].
snip

Simon - just ignore the message and move on. Really.
Synthesis optimizations are quite advanced these days - both
combinatorial and across registers.

Some sort of optimization that may not be obvious to you, may have
combined your register bit with another,
leaving this one "unused". It's ok. Trust the tool,
and just move on.

It's been at least five years since I've actually done FPGA work, but I
always took unexpected optimizations of this sort to mean that I didn't
have my head screwed on straight, and I needed to figure out what I was
doing wrong.

Most of the time, I was right.

--

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com
 

Welcome to EDABoard.com

Sponsor

Back
Top