Page 9 of 16

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 8:59 am
by BigEd
Excellent bug! Can't take interrupts in decimal mode...

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 9:03 am
by Arlet
I know people always wanted decimal interrupts and resets, so I have provided the opportunity here :) You can modify the microcode to have different behavior.

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 9:07 am
by BigEd
Quite an interesting idea to make the D flag swap between two instruction sets, or two interrupt regimes, or something...

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 9:08 am
by Arlet
On a serious note, this little side quest did lead me to a new idea of using the feature of the block RAMs to provide a initial value on the output registers when the FPGA is configured, so it will automatically jump to the reset handler, instead of starting with a BRK.

In addition, the block RAMs have a reset input that can be configured to load a different constant value in the output registers. If I tie this input to the reset input of the CPU, I don't need any logic to handle the resets.

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 9:12 am
by Arlet
BigEd wrote:
Quite an interesting idea to make the D flag swap between two instruction sets, or two interrupt regimes, or something...
There is the limitation that the first cycle of the instruction decoding always comes out of a fixed area, no matter the value of the D flag. That's because the microcode ROM is only 512*32, and I need the first 256 entries to dispatch the opcode. The other 256 entries deal with subsequent cycles, and they are split in 2 banks based on D flag.

Of course, if you're really interested in such a thing, it's easy enough to use 2 ROMs.

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 10:47 am
by Arlet
Arlet wrote:
In addition, the block RAMs have a reset input that can be configured to load a different constant value in the output registers. If I tie this input to the reset input of the CPU, I don't need any logic to handle the resets.
An interesting application could be to have a power-on reset handler using a different vector than the regular reset.

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 12:03 pm
by Arlet
Using the INIT/SRVAL parameters of the block RAM, plus combining the NMI and IRQ in a single select, I managed to get the input mux to the microcode address reduced from 6 choices to 4, which narrows the select signal from 3 bits to 2.

Here's the 9 bit address into the microcode ROM. In the first cycle, we take the opcode as index. After that, each control word contains a pointer to next address. The 'D' bit is set according to decimal flag. When the addressing mode is done, and the effective address is available, the 'finish' handler is called. This allows common operations to be combined with the same microcode. The 'finish' address is set in the first microcode instruction. When an interrupt is taken, the D bit is replaced by bit indicating NMI or IRQ.

Code: Select all

    8   7   6   5   4   3   2   1   0
  +---+---+---+---+---+---+---+---+---+
  | 0 |           opcode (DB)         |   opcode lookup
  +---+---+---+---+---+---+---+---+---+
  | 1 | D |        jmp next           |   next instruction 
  +---+---+---+---+---+---+---+---+---+
  | 1 | D | 1   0 |      finish       |   finish handler 
  +---+---+---+---+---+---+---+---+---+
  | 1 |N/I| 1   1   0   0   0   0   0 |   IRQ/NMI handler @160/@1E0
  +---+---+---+---+---+---+---+---+---+

Re: My new verilog 65C02 core.

Posted: Sat Nov 07, 2020 6:26 pm
by Arlet
I have a test board with a couple of 7 segment displays, driven by a chain of 74HC595s. To access the chain, the CPU can just write a byte to the peripheral port. The problem is that the chain is a bit slow (I bought the wrong devices), and the CPU needs to wait a bit. So I figured this would be a good time to test out the RDY signal in practice, and added a bit of logic to stop the CPU if the SPI was still busy. Works like a charm. Not so good for the interrupt latency, though :)

Re: My new verilog 65C02 core.

Posted: Sun Nov 08, 2020 5:07 pm
by Arlet
I've spent most of the time playing with FPGA hardware. Made a new UART driver, and added timer interrupt. I now have a simple interrupt routine that increments a counter @ 100Hz, and displays it on the 7 segment displays on the board.

But then I noticed that the timer would stop when I entered a command through the UART. It turned out that the JMP (IND) was the problem, because it shares the last couple of cycles with the BRK instruction, including setting the I flag.

I'm surprised that Klaus' test suite didn't catch that.

Microcode is a bit of a double edged sword. It's really flexible and easy to make local adjustments, but it's also much easier to get these subtle bugs that only appear in specific situations. I guess it also doesn't help that my input file is an unreadable wall of binary :)

Re: My new verilog 65C02 core.

Posted: Sun Nov 08, 2020 5:36 pm
by BigEd
Interesting - not the first test escape!

Re: My new verilog 65C02 core.

Posted: Mon Nov 09, 2020 6:39 am
by Arlet
I've started on a tool to translate the microcode binary file to human readable text, so that it's easier to check if it's doing the right things. Here's a sample of the first version's output. It shows all opcodes that update a register in their first cycle.

Maybe later I will also write a tool that goes the other way, and reconstruct a binary file from readable text.

Code: Select all

00: S = S - 1
08: S = S - 1
0A: A = ASL A
1A: A = A + 1
20: S = S - 1
28: S = S + 1
2A: A = ROL A
3A: A = A - 1
40: S = S + 1
48: S = S - 1
4A: A = LSR A
5A: S = S - 1
60: S = S + 1
68: S = S + 1
6A: A = ROR A
7A: S = S + 1
88: Y = Y - 1
8A: A = X
98: A = Y
9A: S = X
A8: Y = A
AA: X = A
BA: X = S
C8: Y = Y + 1
CA: X = X - 1
DA: S = S - 1
E8: X = X + 1
FA: S = S + 1

Re: My new verilog 65C02 core.

Posted: Mon Nov 09, 2020 10:12 am
by Arlet
Flags updates are still missing, and the layout needs to be improved, but here's an example of the BRK instruction sequence decoded.

Code: Select all

00: [9] AB<={01,S}      AH<=DB  PC<=AB+1|               M<=DB   S<=S - 1
    [8] AB<={01,S}                      |   DO=PCH      M<=DB   S<=S - 1
    [8] AB<={01,S}                      |   DO=PCL      M<=DB   S<=S - 1
    [f] AB<=BRK                         |   DO=P        M<=DB   
    [c] AB<=AB+1        AH<=DB          |               M<=DB   
    [2] AB<={DB,AH}     AH<=DB  PC<=AB+1|               M<=DB   
    [c] AB<=AB+1        AH<=DB          |               M<=DB   
The '<=' operator works as in Verilog, indicating that the result is stored in registers at the next clock edge. The '=' operator happens right away, so that's why you see the stack address being loaded in AB one cycle before the corresponding DO value is set.

Re: My new verilog 65C02 core.

Posted: Mon Nov 09, 2020 11:53 am
by Arlet
Full list for all opcodes on GitHub. Still missing everything related to flags, but that will be added soon.

Better version using markdown

Re: My new verilog 65C02 core.

Posted: Tue Nov 10, 2020 6:31 am
by Arlet
I've added all instruction names to the microcode table and also sorted it by instruction/addressing mode.

Re: My new verilog 65C02 core.

Posted: Tue Nov 10, 2020 11:18 am
by Arlet
Here's a simplified schematic block diagram of the core datapath.

The blocks with the little '>' in the corner are registers. The output data on the right lines up with the input data on the left in the next cycle, except for the ABL/ABH on the right go into the memory, and then the DB on the left comes out.