6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu May 09, 2024 10:48 am

All times are UTC




Post new topic Reply to topic  [ 11 posts ] 
Author Message
PostPosted: Sat Dec 17, 2022 8:20 pm 
Offline

Joined: Sat Aug 14, 2021 6:04 pm
Posts: 10
Hilarious AI-generated multiplication function, presented here without further comment.

Code:
; Multiply the 16-bit value in A:X by the 16-bit value in Y:B and store the result in A:X
; Input: A:X = first operand
;        Y:B = second operand
; Output: A:X = product
;         Y:B = undefined
multiply:
    ldy #0                ; Clear Y register
    sta temp_low          ; Save low byte of first operand
    sty temp_high         ; Save high byte of first operand
    stx temp_low+1        ; Save low byte of second operand
    stx temp_high+1       ; Save high byte of second operand
    lda #0                ; Clear A register
    ldx #0                ; Clear X register
loop:
    lsr temp_low+1        ; Shift right second operand
    ror temp_high+1       ; Rotate through carry second operand
    bcc skip              ; Skip add if carry is clear
    clc                   ; Clear carry flag
    lda temp_low          ; Add first operand to A
    adc temp_low+1        ; Add second operand to A
    sta temp_low          ; Save result
    ldx temp_high         ; Add first operand to X
    adc temp_high+1       ; Add second operand to X
    stx temp_high         ; Save result
skip:
    inx                   ; Increment X register
    bne loop              ; Repeat until X overflows
    lda temp_low          ; Load result low byte
    ldx temp_high         ; Load result high byte
    rts                   ; Return from subroutine

temp_low:  .byte 0        ; Temporary storage for low byte of first operand
temp_high: .byte 0        ; Temporary storage for high byte of first operand


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 17, 2022 8:57 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
i've also gotten ChatGPT to write some 6502 assembly. specifically i asked it to write a function that takes a 32-bit fixed point number and calculates the inverse (1/x) of said number.
it always got a bit confused and only made the function save the lowest byte of the result instead of the whole 32-bits. it also sometimes assumes that all registers, not just the Accumulator, can do math. so you end up with fun instructions like "ADC X, A"

but it is fairly adaptable, for example one time it somehow assumed A, X, and Y were 16-bit wide. so i told it that they were only 8-bit wide and it adjusted it's code accordingly. so if you give it a detailed description of what you want, and when noticing any obvious mistakes tell it about them, it can make some decent code.

also this is not 6502 related but i've been working on a Ray Tracer in C using OpenCL because i want to experiment with modern GPUs, so i asked ChatGPT to write a function for me to detect when a ray intersects with a triangle, giving it exact descriptions of input arguments and what i want it to return. and the function worked perfectly without any alterations... which is good because 3D math kinda goes over my head a bit


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 18, 2022 2:47 am 
Offline

Joined: Sat Aug 14, 2021 6:04 pm
Posts: 10
I didn't think to correct it. How did you do that? Can I just say, "Hey, by the way, the 6502 has no B register?"


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 18, 2022 7:52 am 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
yes, it is a chat. like if you were to talk to someone in this forum.
though keep in mind to be specific. so for example if it uses a MUL or DIV Instruction which obviously don't exist on the 6502 tell it "the 6502 has no MUL or DIV Instructions, can you adjust the code to exclude those?"


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 19, 2022 1:16 am 
Offline

Joined: Wed Jan 08, 2014 3:31 pm
Posts: 575
I can pretty quickly spot stuff that looks wrong. But what I wonder is how does it come up with this code? What sort of algorithm could generate something that sort of appears reasonable but is wide of the mark.


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 19, 2022 7:50 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10800
Location: England
It works very like a Markov chain, rather like the pastiches one would see back in the 80s or 90s, with one difference being that the generator has a very deep history, and another that the probability for the next token is based on the prompt and the output so far. Another difference is that it's trained on an enormous body of text taken mostly from the web.

The more specific the prompt, and the more popular the content, the better it will do. I would expect it would do better writing x86 code than 1802 code, for example. If the prompt mentions Commodore and quarter squares, it might do better yet.

The algorithm is terribly simple: it's the data which contains all the complexity. The advances come in being able to digest terrifically large amounts of data.

Markov chains on Usenet in 1994:
https://groups.google.com/g/comp.sys.ap ... XL8ZuHTI4J
and here from 1991
https://groups.google.com/g/soc.motss/c ... wvsdsci5gJ

In BYTE magazine November 1984
A Travesty Generator for Micros

Fred Brooks in the 1950s, as an undergrad, programming the Mark IV at Harvard:
Quote:
So we undertook for our first year project to write a program that would analyze melodies and create synthetic melodies using a eightfold Markovian process. And that took us three years to get done but when—- and the problem is what do you use for a sample. What we needed is a big a corpus as we could get. So we chose common meter hymns because we could find a lot of them that already had the same metrical structure. We transposed them all to the same key then we analyzed the transition probabilities of the melodies. And the interesting question was, is there some order at which you get something that sounds like a human could have written it and yet doesn't replicate a chunk of your sample. And what we found was that at orders five and six that did happen. At seven and eight we replicated sample halves, and at two and three and so forth you wouldn't have mistaken it for human music. But at five and six we got stuff you could pass off on any choir.

Oral History of Fred Brooks; 2007-09-16

Edit: for more detail, perhaps see this article
(via this discussion which is worth a look too especially for the illustrations of failures in simple arithmetic. If you can't always get arithmetic right, surely not a good idea to expect correct code generation.)


Last edited by BigEd on Tue Dec 20, 2022 8:24 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 19, 2022 6:09 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 387
Location: Minnesota
Quote:
It works very like a Markov chain


It's a pity there's no way to upvote a post here. Interesting stuff, reminding us once again that there's not that much new under the sun.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 05, 2023 7:38 pm 
Offline

Joined: Sun Feb 05, 2023 7:34 pm
Posts: 1
I assume we're all aware that the code won't work as shown. Two consecutive STX's, claiming to be the high and low bytes of the second operand, are all I need to see. The fact that the 6502 has no B register is almost irrelevant, since it nowhere attempts to use a B register. Still, it's probably better code, and was undoubtedly written faster, than anything I could produce by hand without a lot of retooling from forty years ago. :-)


Top
 Profile  
Reply with quote  
PostPosted: Mon Feb 06, 2023 3:49 pm 
Offline

Joined: Mon Jan 19, 2004 12:49 pm
Posts: 683
Location: Potsdam, DE
Heh. I've just written a 16*16 = 32 bit unsigned multiply three ways (using the stack, a data stack, and bare memory for variables) and thrown the first two away as over-complex... and I think I'm about to throw the third away too as providing more data than I need. Though it is handy for a base-2 to base-36 integer reader :)

Neil


Top
 Profile  
Reply with quote  
PostPosted: Mon Feb 06, 2023 6:47 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8432
Location: Southern California
barnacle wrote:
Heh. I've just written a 16*16 = 32 bit unsigned multiply three ways (using the stack, a data stack, and bare memory for variables) and thrown the first two away as over-complex... and I think I'm about to throw the third away too as providing more data than I need. Though it is handy for a base-2 to base-36 integer reader :)

Be sure to see our topic at viewtopic.php?t=689, about UM* (multiplication) bug in common 6502 Forths (and my fix).  It also shows some faster variations, with code size and speed comparisons.  Forum member TobyLobster has done extensive work comparing over 60 6502 integer multiply methods, and posted a great compilation here.

_________________
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: Mon Feb 06, 2023 9:44 pm 
Offline

Joined: Mon Jan 19, 2004 12:49 pm
Posts: 683
Location: Potsdam, DE
Yes, I did see that; it was what persuaded me to come up with a larger and slightly more complex multiplication than I actually need, just for the hell of it. (I could cover all my immediate use with an 8x8 = 16 I think, to index into a 60-deep table with 7-byte entries).

This is about as simple as I could come up with but the only optimisations are a fast break if either operand is zero, and a restricted loop through when the multiplicand shifts right to zero. It's not much slower than a 16x16 = 16, just a couple of extra additions per cycle.

Code:
umul:         ; unsigned 16x16 = 32 multiply
            ; multiplicand and multiplier in param_a, param_b
            ; result in result
            ; also thumps param_c as a temp         

   lda #0
   sta result            ; result = 0
   sta result + 1
   sta result + 2
   sta result + 3
   sta param_c
   sta param_c + 1         ; use param_c as extension of param_b
   
   lda param_b
   ora param_b + 1         ; if MPLIER != 0
   beq mul_x
mul_0:   
      lsr param_a + 1      ; MICAND /= 2
      ror param_a
      bcc mul_1         ; if MICAND & 1 == 1
         clc            ; MRESULT += MPLIER
         lda param_b
         adc result
         sta result
         lda param_b + 1
         adc result + 1
         sta result + 1
         lda param_c
         adc result + 2
         sta result + 2
         lda param_c + 1
         adc result + 3
         sta result + 3
mul_1:
      asl param_b         ; MPLIER *= 2
      rol param_b + 1
      rol param_c
      rol param_c + 1
      lda param_a
      ora param_a + 1
      bne mul_0         ; while MICAND != 0
mul_x:
   rts


Of passing parameters: the lack of a base pointer in 6502 (as, say, an 8086 has) makes passing and manipulating data on the return stack a little tricky though sticking the stack pointer in x and indexing above that
Code:
    tsx
    lda $103,x    ; first byte above the return address
    adc $105,x    ; third byte above the return address

works but means that if you use the stack in the calculation, things move around relative to the current stack position. It's also simpler if the calling routine both pushes data on the stack and expects to remove the same amount of data.

Neil


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC


Who is online

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