Page 1 of 2
calculating 65c02 instruction size
Posted: Tue Nov 21, 2023 12:03 pm
by tius
I am sure that there is already a lot of nicer and shorter code for this. But the code seems to do the job and allows for memory dumps that are a easier to read.
Maybe this is useful for someone. Comments and suggestions for improvement are very welcome.
Code: Select all
; input:
; A opcode
; changed:
; A
; output
; X instruction size
; remarks:
; - valid for newer 65c02 with BBR, BBS, RMB and SMB instructions
; see also:
; - https://llx.com/Neil/a2/opcodes.html
; - http://www.6502.org/tutorials/65c02opcodes.html
instruction_size:
ldx #3
eor #$0c
bit #$0c
beq @three ; xC, xD, xE, xF
; x0 .. xB
eor #$08
bit #$0c
beq @two ; x4, x5, x6, x7
; x0 .. x3, x8 .. xF
eor #$03
bit #$03
beq @one ; x3, xB
; x0 .. x2, x8 .. xA
bit #$08
beq @x0_2 ; x0 .. x2
; x8 .. xA
bit #$01
bne @one ; x8, xA
; x9
bit #$10
beq @two ; 09, 29, ..., e9
bne @three ; 19, 39, ..., f9
; x0 .. x2
@x0_2: eor #$03
bit #$03
bne @two ; x1, x2
; x0
bit #$80
bne @two ; 80, 90, .., F0
; 00, 10, ..., 70
bit #$10
bne @two ; 10, 30, 50, 70
; 00, 20, 40, 60
cmp #$24
beq @three ; 20
; 00, 40, 60
@one: dex
@two: dex
@three: rts
Example dump using the code:
Code: Select all
.i f80d
.: F80D 48
.: F80E DA
.: F80F BA
.: F810 BD 03 01
.: F813 29 10
.: F815 D0 03
.: F817 6C 02 02
.: F81A 6C 04 02
update (2023-12-07):
As BB8 pointed out (
viewtopic.php?f=2&t=7845&p=104965#p104946), result 1 for x7 and xF is no longer correct for current 65c02. I have adapted the code accordingly.
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 9:06 am
by rudla.kudla
I posted similar table based routine in this thread:
viewtopic.php?f=2&t=7496
We can compare notes

Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 9:12 am
by barnacle
I really need to get my head around just how the bit instruction works... I don't think I've *ever* used it.
Neil
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 9:27 am
by tius
I really need to get my head around just how the bit instruction works... I don't think I've *ever* used it.
Neil
It is used like a regular
here to test for bits, however without loosing the value of A. This mode is not available with the NMOS 6502.
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 9:31 am
by tius
I like your approach because it also works with the 6502. Does it also deliver the correct results for the legal and illegal opcodes of the 65c02?
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 9:59 am
by GARTHWILSON
I really need to get my head around just how the bit instruction works... I don't think I've *ever* used it.
I hope it's ok to attach this. It's a page scanned from my paper copy of "Programming the 65816—Including the 6502, 65C02 and 65802" 6502/65816 programmer's manual by David Eyes and Ron Lichty, which I bought in the 1990's. Even though WDC is charging for it again, they had it for free download for many years. I'm justifying the post by thinking maybe it will encourage more people to get the whole manual. 
From my links page:
This is definitely the best 65xx programming manual available, and a must-have for every 65xx programmer! It starts with the basics, followed by architecture, the CMOS 65c02's many improvements over the original NMOS 6502 including added instructions and addressing modes and fixing the NMOS's bugs and quirks, and then the natural progression to the 65816; a thorough tutorial, writing applications, then very detailed and diagrammed information on all 34 addressing modes, at least a page of very detailed description for each instruction, with info on every addressing mode available for that instruction, then instruction lists, tables, and groups, of all 255 active op codes, plus more. 469 pages. From Western Design Center. (.pdf) Note: There were many problems with the earlier .pdf version that were not in the original paper manual; but in late March 2015, WDC scanned and OCR'ed the paper manual and posted the new, repaired .pdf.
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 10:55 am
by barnacle
Ah, thanks. So it can test any bit(s) including 6 and 7 that get transferred anyway... I had it for some reason that it could _only_ read those bits... I should read the docs better.
Neil
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 1:15 pm
by Dr Jefyll
"When the BIT instruction is used with the immediate addressing mode, the n and v flags are unaffected."
Whoa! -- probably I used to know that, but it's good to have a reminder.
One would hardly expect the presence or absence of a flag update to vary according to which address mode an instruction is using.

Still, I think I understand the decision to have BIT immediate behave anomalously.
-- Jeff
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 5:45 pm
by BigDumbDinosaur
I really need to get my head around just how the bit instruction works... I don't think I've *ever* used it.
You need to get out more often and do I/O programming.
You’d get a lot of use out of BIT.
The below is redundant, but so be it.
BIT is a non-destructive logical AND of the accumulator with memory. BIT conditions the z flag in the status register (SR) according to the result of the logical AND, but does not save the computed result anywhere. Additionally, when BIT is used on memory, it will copy bits 6 and 7 of the tested memory location into the v and n SR flags, which is quite convenient when checking flags conditioned by some earlier program behavior:
Code: Select all
;contrived example of using BIT on a memory location...
;
LDA #%01000000 ;set bit 6...
STA FLAG ;of this flag
;
; ...do some stuff...
;
BIT FLAG ;test our flag
BVS TOHERE ;bit 6 set, so take the branch
The CMOS MPUs added the BIT immediate instruction, which is convenient for random bit-testing of a value loaded into the accumulator:
Code: Select all
;contrived use of BIT immediate with a 65C22 — won’t work with NMOS 6502...
;
LDA VIA1IFR ;read VIA #1’s interrupt flag register
BPL NOTVIA1 ;not interrupting
;
STA VIA1IFR ;crude hack...clears all pending VIA #1 IRQs
BIT #%00000100 ;shift register calling?
BEQ NOT_SR ;no, must be something else
;
;
; shift register needs attention...
;
PHA ;save IFR state
;
; ...do shift register stuff...
;
PLA ;recall IFR state & fall thru
;
NOT_SR BIT #%00100000 ;timer B calling?
BEQ NOT_TIMB ;no, must be something else
;
;
; timer B need attention...
;
PHA ;save IFR state
;
; ...do timer B stuff...
;
PLA ;recall IFR state & fall thru
;
NOT_TIMB ...onward we go...
;
NOTVIA1 ...jump around VIA #1 IRQ code...
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 5:55 pm
by floobydust
As BDD noted, I/O programming can make good use of the BIT instruction. Attached is a snippet of my C02 Pocket BIOS which supports the SC28L92 DUART.
Code: Select all
;**************************************************************************************************
;
;This is the IRQ handler entry point for the SC28L92 DUART.
; This is the first IRQ handler unless an IDE device is found during cold start.
; By default, it will take 25 clock cycles to arrive here after an interrupt is
; generated. If an IDE device is present, the IDE handler will be processed
; first. If no IDE interrupt is active, it will take an additional 33 cycles to
; arrive here.
;
; C02BIOS 4.02 has re-arranged the interrupt handler for the SC28L92 DUART.
; - The second port is checked first for active data, as it could be used for a
; - high-speed transfer from another device. The first port is used for the
; - console (which can also be used for data transfer) and is checked second.
; - The Counter/Timer is checked first, to maintain benchmark and delay accuracy.
;
INTERUPT0 ;Interrupt 0 to handle the SC28L92 DUART
LDA UART_ISR ;Get the UART Interrupt Status Register (4)
BEQ REGEXT_0 ;If no bits are set, exit handler (2/3)
;
BIT #%00001000 ;Test for Counter ready (RTC) (2)
BNE UART_RTC ;If yes, go increment RTC variables (2/3)
;
BIT #%01000000 ;Test for Break on B (2)
BNE UARTB_BRK ;If yes, Reset the DUART receiver (2/3)
;
BIT #%00100000 ;Test for RHR B having data (2)
BNE UARTB_RCV ;If yes, put the data in the buffer (2/3)
;
BIT #%00010000 ;Test for THR B ready to receive data (2)
BNE UARTB_XMT ;If yes, get data from the buffer (2/3)
;
BIT #%00000100 ;Test for Break on A (2)
BNE UARTA_BRK ;If yes, Reset the DUART receiver (2/3)
;
BIT #%00000010 ;Test for RHR A having data (2)
BNE UARTA_RCV ;If yes, put the data in the buffer (2/3)
;
BIT #%00000001 ;Test for THR A ready to receive data (2)
BNE UARTA_XMT ;If yes, get data from the buffer (2/3)
;
; if none of the above bits caused the IRQ, the only bit left is the change input port.
; just save it in the temp IRT register in page zero and exit.
;
STA UART_IRT ;Save the 28L92 ISR for later use (3)
REGEXT_0 JMP (IRQRTVEC0) ;Return to Exit/ROM IRQ handler (6)
;
UART_RTC JMP UART_RTC0 ;Jump to RTC handler (3)
;
;**************************************************************************************************
BIT is also used in the DUART IRQ handlers for checking the receive and transmit holding registers for both ports... very handy instruction!
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 6:38 pm
by gfoot
A couple more examples of slightly different usages - first, waiting for specific bits to be set e.g. in I/O flag registers, with low latency in responding when they are:
Code: Select all
; Wait for the shift register interrupt flag to be set
lda #$04
wait_for_sr:
bit VIA_IFR : beq wait_for_sr
; Send the parity and stop bits
tya : ror : ror : ora #$7f : sta VIA_SR
; Wait for T2
lda #$20
wait_for_t2:
bit VIA_IFR : beq wait_for_t2
...
And secondly, quickly checking in an IRQ handler which device caused the interrupt, without needing to stack the A register first:
Code: Select all
irq:
; Check for serial interrupts
bit SER_STAT
bmi irq_serial
; Check for VIA interrupts
bit VIA_IFR
bmi irq_via
rti
This latter syntax can also be good for checking for error conditions after calling subroutines, if you have the convention that on error the subroutine will store an error code in e.g. a known zero page location, with the top bit set. Then you can check for errors using "bit $ff : bmi error" without corrupting any registers that the subroutine may have returned values in. The BBC Micro has a flag there which is set by an interrupt handler whenever the Escape key is pressed, so code that wants to be escapable can easily check for that with just a couple of instructions.
This case where no registers are corrupted is really useful, and note that you can also act based on bit 6 just as easily as bit 7.
Re: calculating 65c02 instruction size
Posted: Wed Nov 22, 2023 6:40 pm
by BigDumbDinosaur
As BDD noted, I/O programming can make good use of the BIT instruction. Attached is a snippet of my C02 Pocket BIOS which supports the SC28L92 DUART...
I do something similar in the firmware for my POC units, making extensive use of BIT immediate, as well as that “useless” (<dp>,X) addressing mode.
Here's the portion of the IRQ handler that processes receiver interrupts:
Code: Select all
03603 ; —-—-—-—-—-—-—-—-—-—-—-—
03604 ; SIO Receiver Processing
03605 ; —-—-—-—-—-—-—-—-—-—-—-—
03606 ;
03607 00D2CF 85 4A sta sioirqst ;save interrupt status
03608 00D2D1 A0 00 ldy #0 ;1st channel to process
03609 ;
03610 00D2D3 46 4A .0000010 lsr sioirqst ;this channel interrupting?
03611 00D2D5 90 32 bcc .0000040 ;no
03612 ;
03613 00D2D7 98 tya ;copy channel index &...
03614 00D2D8 0A asl ;make channel pointer...
03615 00D2D9 AA tax ;offset
03616 00D2DA A9 40 lda #nxpcresr ;clear any RxD...
03617 00D2DC 81 18 sta (siocr,x) ;overrun (ugly hack)
03618 ;
03619 00D2DE A1 10 .0000020 lda (siosr,x) ;get receiver status
03620 00D2E0 89 01 bit #nxprxdr ;RHR empty?
03621 00D2E2 F0 11 beq .0000030 ;yes, done with channel
03622 ;
03623 00D2E4 A1 20 lda (siofif,x) ;no, get datum from RHR
03624 00D2E6 EB xba ;protect it for now
03625 00D2E7 B5 30 lda sioputrx,x ;get queue ‘put’ pointer
03626 00D2E9 1A inc ;bump it
03627 00D2EA D5 28 cmp siogetrx,x ;any room in queue?
03628 00D2EC F0 F0 beq .0000020 ;no, discard datum
03629 ;
03630 00D2EE EB xba ;store datum ...
03631 00D2EF 81 30 sta (sioputrx,x) ;in queue
03632 00D2F1 F6 30 inc sioputrx,x ;adjust ‘put’ pointer &...
03633 00D2F3 80 E9 bra .0000020 ;process next datum
03634 ;
03635 00D2F5 38 .0000030 sec
03636 00D2F6 B5 30 lda sioputrx,x ;compute datums...
03637 00D2F8 F5 28 sbc siogetrx,x ;in queue
03638 00D2FA C9 E7 cmp #s_siohwm ;reach queue fill level?
03639 00D2FC 90 0B bcc .0000040 ;no
03640 ;
03641 00D2FE BD 0B EF lda siotstab,x ;yes, tell ourselves we’re...
03642 00D301 04 48 tsb siorxst ;deasserting RTS
03643 00D303 D0 04 bne .0000040 ;RTS already deasserted
03644 ;
03645 00D305 A9 90 lda #nxpcrrsd ;tell DUART to...
03646 00D307 81 18 sta (siocr,x) ;deassert RTS
03647 ;
03648 00D309 C8 .0000040 iny ;next channel
03649 00D30A CC 0C C0 cpy io_quart+nx_urega ;all channels processed?
03650 00D30D D0 C4 bne .0000010 ;no
Upon entry to this code section, an IRQ status has already been loaded into .A and is stored at sioirqst for later manipulation. Locations such as siocr (channel command) and siosr (channel status) are direct (zero) page pointers to individual chip registers, these having been set up during first-stage POST.
Since I have two DUARTs in the system, which are made to appear to higher-level code as a single quadruple-channel UART, I have made extensive use of loops and pointers, as well as bit fields, to constrain code size and at the same time, improve throughput. In this application, BIT immediate, as well as some 65C816-unique instructions, e.g., XBA, become invaluable. Indeed, without BIT immediate, significantly more code would be required to get the job done, plus I’d be forced to use some additional direct page to store intermediate results.
Incidentally, although the above is written in 65C816 assembly language, only trivial changes would be required to adapt it to a 65C02 system.
Re: calculating 65c02 instruction size
Posted: Fri Nov 24, 2023 2:48 pm
by BruceRMcF
"When the BIT instruction is used with the immediate addressing mode, the n and v flags are unaffected."
Whoa! -- probably I used to know that, but it's good to have a reminder.
One would hardly expect the presence or absence of a flag update to vary according to which address mode an instruction is using.

Still, I think I understand the decision to have BIT immediate behave anomalously. ...
Yes, since the state of the N and V flags would be determined by the immediate operand, setting those flags is never going to give new information. So if it ever might be convenient to leave them untouched for some BIT operations, may as well make "BIT #u" the one that leaves them untouched.
Re: calculating 65c02 instruction size
Posted: Mon Nov 27, 2023 2:24 pm
by rudla.kudla
I like your approach because it also works with the 6502. Does it also deliver the correct results for the legal and illegal opcodes of the 65c02?
Currently it does not. I only prepared the tables for legal opcodes.
But maybe it could

Re: calculating 65c02 instruction size
Posted: Sat Dec 02, 2023 5:51 pm
by Osi
Hi tius,
to calculate the instruction length for a 6502 CPU, here the code I'm using in one of my programs:
instruction_size:
ldx #$01
cmp #$00
beq done
cmp #$40
beq done
cmp #$60
beq done
ldx #$03
cmp #$20
beq done
and #$1F
cmp #$19
beq done
and #$0F
tax
lda table,x
tax
done: rts
table:
.db $02 ,$02 ,$02 ,$01 ,$02 ,$02 ,$02 ,$01 ; Opcode length table
.db $01, $02 ,$01 ,$01 ,$03 ,$03 ,$03 ,$03
Thomas