6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu May 02, 2024 5:26 am

All times are UTC




Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Tue Nov 21, 2023 12:03 pm 
Offline
User avatar

Joined: Fri Nov 05, 2021 1:06 pm
Posts: 20
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:
;   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:
.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 (http://forum.6502.org/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.


Last edited by tius on Thu Dec 07, 2023 10:14 pm, edited 3 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 9:06 am 
Offline

Joined: Tue Apr 20, 2010 4:02 pm
Posts: 31
I posted similar table based routine in this thread:

http://forum.6502.org/viewtopic.php?f=2&t=7496

We can compare notes :-)


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 9:12 am 
Offline

Joined: Mon Jan 19, 2004 12:49 pm
Posts: 674
Location: Potsdam, DE
I really need to get my head around just how the bit instruction works... I don't think I've *ever* used it.

Neil


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 9:27 am 
Offline
User avatar

Joined: Fri Nov 05, 2021 1:06 pm
Posts: 20
barnacle wrote:
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
Code:
AND #
here to test for bits, however without loosing the value of A. This mode is not available with the NMOS 6502.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 9:31 am 
Offline
User avatar

Joined: Fri Nov 05, 2021 1:06 pm
Posts: 20
rudla.kudla wrote:
I posted similar table based routine in this thread:
http://forum.6502.org/viewtopic.php?f=2&t=7496
We can compare notes :-)

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?


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 9:59 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8429
Location: Southern California
barnacle wrote:
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. :D

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.


Attachments:
65bitInst.gif
65bitInst.gif [ 166.71 KiB | Viewed 2387 times ]

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 10:55 am 
Offline

Joined: Mon Jan 19, 2004 12:49 pm
Posts: 674
Location: Potsdam, DE
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


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 1:15 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3350
Location: Ontario, Canada
"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. :shock: Still, I think I understand the decision to have BIT immediate behave anomalously.

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 5:45 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8169
Location: Midwestern USA
barnacle wrote:
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.  :D  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:
;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:
;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...

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Wed Nov 22, 2023 5:57 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 5:55 pm 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1373
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:
;**************************************************************************************************
;
;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!

_________________
Regards, KM
https://github.com/floobydust


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 6:38 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
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:
    ; 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:
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.


Last edited by gfoot on Wed Nov 22, 2023 6:42 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 6:40 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8169
Location: Midwestern USA
floobydust wrote:
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.  :D  Here's the portion of the IRQ handler that processes receiver interrupts:

Code:
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.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 24, 2023 2:48 pm 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
Dr Jefyll wrote:
"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. :shock: 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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 27, 2023 2:24 pm 
Offline

Joined: Tue Apr 20, 2010 4:02 pm
Posts: 31
tius wrote:
rudla.kudla wrote:
I posted similar table based routine in this thread:
http://forum.6502.org/viewtopic.php?f=2&t=7496
We can compare notes :-)

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 :-)


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 02, 2023 5:51 pm 
Offline
User avatar

Joined: Wed May 11, 2022 10:34 am
Posts: 16
Location: Germany
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


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

All times are UTC


Who is online

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