6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 10:13 pm

All times are UTC




Post new topic Reply to topic  [ 609 posts ]  Go to page Previous  1 ... 19, 20, 21, 22, 23, 24, 25 ... 41  Next
Author Message
PostPosted: Thu Mar 14, 2013 10:37 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
If you don't count the code for the straight line segments, and the sine tables, the polygon method takes less code. And like I said, it works well for partial circles. The Bresenham circle algorithm is probably the fastest, if implemented well.


Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 15, 2013 1:49 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
I'm going to bring back the hardware Random Number Generator for some speed tests with randomly placed origins, colors, radii, etc.
Also I would like to try filled circles, which would be done by decreasing the max radius by one until zero and plotting the circles around each origin. Also, if there's 8 quadrants I can envision some kind of math affecting the color to simulate a kind of light source to make a 3d effect. Just thinking as for an experiment. I'm not hell bent on it.
Also, I want to do a spiral where the radius decreased by some amount before the circumference is complete.

I would like to do all this without the use if lookup tables, load down the system then do a comparison with the LUT's. I have plenty of blockRAM left.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 15, 2013 2:12 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
I tried the fill circle by reducing the radius but it leaves holes scattered. My 320x240 display modified the circle routine to draw horizontal lines from top to bottom, using the endpoints calculated by the original circle routine. It runs fast and leaves no holes. I do not have 65c02 code for it but its not hard to figure out.

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 15, 2013 2:43 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
8BIT wrote:
I tried the fill circle by reducing the radius but it leaves holes scattered...Daryl

Yes, this is what I would've expected too. We have several algorithms donated now. Might be good to check them all out. I just checked out Lee's since I have it in my system already. But you can see also where there should have been some vertical tracing at the very right edge, but there is nothing. And this error eats its way to the center, but the rest seems ok.

Just in case I made an error in the code, I post it... Been a long day at work, but this is some good motivating stuff!

Code:
START:       LDA #$0000
            TAZP                 ;SET ZEROPAGE @$0000_0000
            LDA #$0001
            TASP                 ;SET STACKPAGE @$0001_0000
           
            LDWi $0000           ;  LDW #$0000 - SET BLACK SCREEN ACCORDING TO COLOR LUT
            LDBaw COLTABLE       ;  LDB COLTABLE,w
            STBzp SCRCOL          ;  STB SCRCOL
            JSR CLRSCR
           
            LDWi $0005           ;  LDW #$0005 - SET PIXEL COLOR GREEN ACCORDING TO COLOR LUT
            LDBaw COLTABLE       ;  LDB COLTABLE,w
            STBzp PXLCOL         ; B ACCUMULATOR, PIXELCOLOR
            LDA #$0000
            STA Numberh
            LDFi $00F0           ;F ACCUMULATOR, RADIUS
AD          STFzp Number         ;RADIUS
            JSR Square
            LDA Sqr
            STA RSQR             ;RSQR= R^2
            CLC
           
            LDWi $0000           ; LDW #$0000
           
AC          LDA #$0140           ; X CENTER OF 640x480 SCREEN
            STA SCRLO
            LDA #$80F0           ; Y CENTER OF 640x480 SCREEN
            STA SCRHI            ; START @ORIGIN
                       
            STWzp Number         ; This 'Number' is actually X
            JSR Square           ; Now square it!
            LDA RSQR             ; Radius SQUARED
            SBC Sqr              ; Sqr=Number^2
            STA Numberl          ; This Numberl IS (R^2-X^2)
            JSR SqRoot           ; THIS ROUTINE WILL RETURN Root=SQRT(Numberl)
           
            TWY
            LDA SCRHI            ;A ACCUMULATOR, Y COORDINATE
            SBCAopCzp Root       ;C ACCUMULATOR, Y MATH
            STCzp SCRHI
            STBiy SCRLO          ;PLOT 1st Quadrant
            ADCAopCzp Root
            STCzp SCRHI
            STBiy SCRLO          ;PLOT 2nd Quadrant
                                   
            INW
            CPWi $00EF           ; CPW #$00EF
            BNE AC
            DECF
            CMPFi $0000
            BNE AD
           
END         JMP END


Attachments:
P1000967.JPG
P1000967.JPG [ 51.9 KiB | Viewed 934 times ]

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502
Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 15, 2013 10:34 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Maybe a better way would be to draw lines from the center to the circumference.

Daryl you wouldn't happen to have Bresenham line algorithm would you?

EDIT: Sorry, I missed this part of your post originally:
8BIT wrote:
...using the endpoints calculated by the original circle routine...

Daryl

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 15, 2013 12:31 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
If I understand you correctly, drawing something like a radar sweep? I have line drawing routines that work relatively well, but I think you will still end up with holes.

If you look closely at my circle routine, you see that it only calculates points over a 45 degree arc. It then just uses the mirror image to calculate the other 7 arcs that complete the circle.

x = 0-45 - calculated
x1 = 90 - x
x2 = 90 + x
x3 = 180 - x
x4 = 180 + x
x5 = 270 - x
x6 = 270 + x
x7 = 360 - x

By choosing two of the end points in pairs, you just draw a horizontal line which is much faster than a sloped line.

x1 to x2
x to x3
x4 to x7
x5 to x6

This can also be done with vertical lines equally fast.

Hope this helps.

BTW, here is the line code (unedited from cc65 this time... you will need to edit it some and convert the local lables to globals)

All variables are in ZP. Some are two byte, others are one byte.

Code:
; ------------------------------------------------------------------------
; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
; X2/Y2 = ptr3/ptr4 using the current drawing color.
;
; Must set an error code: NO
;

LINE:

@CHECK: lda     X2           ;Make sure x1<x2
        sec
        sbc     X1
        tax
        lda     X2+1
        sbc     X1+1
        bpl     @CONT
        lda     Y2           ;If not, swap P1 and P2
        ldy     Y1
        sta     Y1
        sty     Y2
        lda     Y2+1
        ldy     Y1+1
        sta     Y1+1
        sty     Y2+1
        lda     X1
        ldy     X2
        sty     X1
        sta     X2
        lda     X2+1
        ldy     X1+1
        sta     X1+1
        sty     X2+1
        bcc     @CHECK

@CONT:  lsr
     sta     DX+1
        txa         
        ror      
        sta     DX
        bne     @NVT 
        jmp     @VERT
@NVT:   stz     IX
        stz     IY   
        sec
        lda     Y2           ;Calculate dy
        sbc     Y1
        bne     @NHZ
     jmp     @HORZ
@NHZ:     bcc       @YNEG
@YPOS:  lsr
        sta     DY
        jsr    SETPIXELCLIP      ;plot first point
@LOOP0: ldx     #$00
@LOOP:  clc
        lda     IX
        adc     DX
        sta     IX
        bcc     @LOOP1
        inx
        inc     X1
        bne     @LOOP1
        inc     X1+1
@LOOP1: clc
        lda     IY
        adc     DY
        sta     IY
        bcc     @LOOP2
     inx
        INC     Y1 
@LOOP2: txa
        beq     @LOOP     ; no adjustment yet
        jsr    SETPIXELCLIP
        lda    DX
        beq    @END0      ; if DX=0, skip x end test
        lda     X1
        cmp     X2
        bne     @END0
        lda     X1+1
        cmp     X2+1
        beq     @END
@END0:  lda     DY
        beq     @LOOP0    ; if dy=0, skip y end test   
        lda     Y1
        cmp     Y2
        bne     @LOOP0    ; reset x=0         
@END:   lda     X2
        sta     X1
        lda     X2+1
        sta     X1+1
        lda     Y2
        sta     Y1
        jsr     SETPIXELCLIP
     rts   

@YNEG:  jsr     SETPIXELCLIP      ;plot first point
        lda     Y1
        sec
        sbc     Y2
        lsr
        sta     DY
@LOOPX: ldx     #$00
@LOOP3: clc
        lda     IX
        adc     DX
        sta     IX
        bcc     @LOOP4
        inx
        inc     X1
        bne     @LOOP4
        inc     X1+1
@LOOP4: clc
        lda     IY
        adc     DY
        sta     IY
        bcc     @LOOP5
     inx
        DEC     Y1 
@LOOP5: txa
        beq     @LOOP3     ; no adjustment yet
        jsr    SETPIXELCLIP
        lda     DX
        beq     @LOOP6      ; if DX=0, skip x end test
        lda     X1
        cmp     X2
        bne     @LOOP6
        lda     X1+1
        cmp     X2+1
        beq     @END
@LOOP6: lda     DY
        beq     @LOOPX      ; reset x
        lda     Y1
        cmp     Y2
        beq     @END
        bra     @LOOPX         

@VERT:  sec
        lda     Y2           ;Calculate dy
        sbc     Y1
     bcc       @VNEG
        bra     @VP2
@VP1:   inc    Y1
@VP2:   jsr    SETPIXELCLIP
        sec
     lda    Y2
        sbc    Y1
        bne    @VP1
        rts
@VN1:   dec    Y1
@VNEG:  jsr    SETPIXELCLIP
        sec
     lda    Y2
        sbc    Y1
        bne    @VN1
        rts

@HRZ:   inc    X1
        bne    @HORZ
        inc    X1+1
@HORZ:  jsr    SETPIXELCLIP
        sec
     lda    X2
        sbc    X1
        bne    @HRZ
        lda    X2+1
        sbc    X1+1
        bne    @HRZ
        rts


Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 15, 2013 12:52 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
Guess I should explain the method for the line drawing routine. I thought this up myself about 30 years ago but doubt that it's an original idea.

First set it up so you increment from x1 to x2, swapping the two points if needed.
You calculate the difference between x1 and x2, store it in dx. Do the same for y1 and y2 stored in dy.
Test for vertical or horizontal lines, and move to optimized code for either.

Now test to see if you will increment or decrement y and point to the proper code section.

Create new variables ix and iy and set to zero. Now, simply add dx to ix and if it carries, inc x1. Then add dy to iy and if it carries, increment y1 (or decrement based in the test above). Plot the new x1,y1 point only when x1 or y1 change.

Keep adding dx to ix and dy to iy until x1 reaches x2.

The loop cycles more times but since there is no multiplication or division, it runs quite fast.

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 15, 2013 2:32 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Awesome. That's all I need is the code. I can work with that and adapt it. Again, thanks a million!

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 10:06 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Added a random number generator. So far it's only being used for the color look up table for plotting pixels. So the pic above is now made of randomized pixels. Also, in a separate experiment, I made it so each concentric circle had its own color as I was originally trying to perform a filled-in circle.
The idea now is to use the RNG to plot many circles, each with a random radius, position and color as fast as 65Org16 machinely possible.

Also, I've been working on a simple start/stop counter based on the 100MHz clock to quantify testing. I already think I know which one will be the highest speed, so I will concentrate first on the accuracy of the timer, then on that conversion to 65Org16 on my next 2 days off.

I have my timer circuit almost done in Verilog. 2 things left for the timer, then to plot characters utilizing the new plotting setup using indirect indexed. This way I'll be able to plot the timing results, I will need text!

I decided to post the code now, even though the reset bit isn't working on the counter yet...just in case anyone sees a better way of an overall Timer construction! I'm thinking this Timer is using too many resources.

I use extremely loose address decoding in order to save FPGA resources.

Code:
`timescale 1ns / 1ps

module Timer(input clk,
             input [15:0] cpuDO,            //cpu databus out
             input cpuWE,                  //cpu write, active high
             input cntrCS,                  //active high from $c000_0000-$cfff_ffff
             output reg [15:0] countDO      //from count [15:0] to cpuDataIn
             );

reg [19:0] counter = 0;      //main .01sec counter from 100MHz clock

reg [4:0] seconds = 0;      //up to 32 seconds
reg [3:0] tens = 0;         //10 tenths
reg [6:0] hundreds = 0;      //100 hundredths

wire [15:0] count;

reg stp = 0;                //control bit for stop
reg res = 0;               //control bit for reset main .01sec counter

assign count [15:0] = {seconds,tens,hundreds};  //assign the bit values when reading the counter

always @(posedge clk)
   if(cntrCS) begin
      if(cpuWE) begin
         res <= cpuDO [15];            //write to $c000_0000, bit 15 = reset
         stp <= cpuDO [14];            //write to $c000_0000, bit 14 = stop
      end
         else 
         countDO <= count;      //read from $c000_0000 16-bit count {sec,tens,hundreds} = xxxxx_xxxx_xxxxxxx
   end
   else countDO <= 16'h0000;

always @(posedge clk) begin
      if (res)
         counter <= 20'b0000_0000_0000_0000_0000;
      
      if (tens == 4'b1001) begin
         tens <= 4'b0000;
         seconds <= seconds + 1;
      end
      else if (hundreds == 7'b110_0011) begin
         hundreds <= 7'b0000000;
         tens <= tens + 1;
      end
            
      if (stp)
         counter <= counter;
         else if (counter >= 20'b1111_0100_0010_0011_1111) begin    //0 to 999,999 for .01sec counter
         counter <= 20'b0000_0000_0000_0000_0000;
         hundreds <= hundreds + 1;
         end
            else
            counter <= counter + 1;
end
         
endmodule

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 19, 2013 10:51 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
This works, now onto converting Daryl's Bresenham...
Added toggle to reset:
Code:
module Timer(input clk,
             input [15:0] cpuDO,            //cpu databus out
             input cpuWE,                  //cpu write, active high
             input cntrCS,                  //active high from $c000_0000-$cfff_ffff
             output reg [15:0] countDO      //from cpuDataOut
             );

reg [19:0] counter = 0;      //main .01sec counter from 100MHz clock

reg [4:0] seconds = 0;      //up to 31.99 seconds
reg [3:0] tens = 0;         //10 tenths (0..9)
reg [6:0] hundreds = 0;      //100 hundredths 0..99)

wire [15:0] count;

reg stp = 0;                //control bit for stop(hold)
reg res = 0;               //control bit to reset main .01sec counter

assign count [15:0] = {seconds,tens,hundreds};  //assign the bit values ($xxxxx_xxxx_xxxxxxx) when reading the counter

always @(posedge clk) begin
   if(cntrCS & cpuWE) begin
         res <= cpuDO [15];            //a write to $c000_0000, bit 15 = reset
         stp <= cpuDO [14];            //a write to $c000_0000, bit 14 = stop
      end
   if(cntrCS & !cpuWE)
      countDO [15:0] <= count [15:0];   //read from $c000_0000 16-bit count {sec,tens,hundreds} = xxxxx_xxxx_xxxxxxx
         else
         countDO [15:0] <= 16'h0000;
   if (res)
      res <= ~res;                     //auto toggle back to count
end

always @(posedge clk) begin
      if (res)
      counter <= 20'b0000_0000_0000_0000_0000;
         else if (stp)
         counter <= counter;
      else begin
         if (tens == 4'b1001) begin
            tens <= 4'b0000;
            seconds <= seconds + 5'b0_0001;
         end
            else if (hundreds == 7'b110_0011) begin
               hundreds <= 7'b000_0000;
               tens <= tens + 4'b0001;
            end
               else begin
                  if (counter >= 20'b1111_0100_0010_0011_1111) begin    //0 to 999,999 for .01sec counter
                  counter <= 20'b0000_0000_0000_0000_0000;
                  hundreds <= hundreds + 7'b000_0001;
                  end
                     else
                     counter <= counter + 20'b0000_0000_0000_0000_0001;
               end
      end
end
         
endmodule


EDIT: Sorry, reposted code several times. This one is final.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 19, 2013 3:31 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Hmmm, I thought I would do a character plot routine in order to plot the result of the Timer before doing the circle routine. So I finished already and came to the realization that video memory would be best placed at the very bottom $0000_0000-$0fff_ffff. Then the 64K zero-page and 64K stack sit above this. All is working. Now I must do a 'plot number' routine and adapt it to the output of the Timer module.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 19, 2013 6:22 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
woops, I realized I don't need a tenths counter. Just 2 8 bit counters that max at 99, 1 for seconds and 1 for 10ths and 100ths :oops:
I'll try to adapt a bit of Verilog code I have in a book that converts 8-bit binary to BCD.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 19, 2013 6:43 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Instead of 7'b110_0011 I would prefer to write 7'd99.

And if you want BCD, it's easier to make a BCD counter than it is to make a binary counter + binary to BCD converter.


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 19, 2013 6:51 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Of course! Thank you!
I need to refresh my memory with some old school TTL datasheets. Vague memories are there with a great many cobwebs from when I first experimented with counters and 7-segment displays on a breadboard.

EDIT: I was on the right track, just trying to be to fancy for my own good. Hopefully I can get this timer section (Verilog & software) done today.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 19, 2013 10:02 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
ARG, I HATE GHOSTS IN THE MACHINE!
I would've been done 5 min's after the last post if it wasn't for the ghost. Old variables (with same names) in ISim were not changing, and I was chasing my tail. Now I'm going on to write this easy HEX plotting software!
Code:
module Timer(input clk,
             input [15:0] cpuDO,            //cpu databus out
             input cpuWE,                  //cpu write, active high
             input cntrCS,                  //active high from $c000_0000-$cfff_ffff
             output reg [15:0] countDO      //from cpuDataOut
             );

reg [16:0] counter = 0;      //main .001sec counter from 100MHz clock

reg [3:0] seconds = 0;      
reg [3:0] tenths = 0;
reg [3:0] hundredths = 0;      
reg [3:0] thousandths = 0;

wire [15:0] count;

reg stp = 0;                //control bit for stop(hold)
reg res = 0;               //control bit to reset main .001sec counter

assign count [15:0] = {seconds, tenths, hundredths, thousandths};  //assign the bit values when reading the counter

always @(posedge clk) begin
   if(cntrCS & cpuWE) begin
         res <= cpuDO [15];            //a write to $c000_0000, bit 15 = reset
         stp <= cpuDO [14];            //a write to $c000_0000, bit 14 = stop
      end
   if(cntrCS & !cpuWE)
      countDO [15:0] <= count [15:0];   //read from $c000_0000 16-bit BCD count
         else
         countDO [15:0] <= 16'h0000;
   if (res)
      res <= ~res;                     //auto toggle back to count
end

always @(posedge clk) begin
      if (res)
         counter <= 17'd0;
         else if
            (stp) counter <= counter;
            else begin
                if (tenths == 4'd9) begin
                     tenths <= 4'd0;
                     seconds <= seconds + 4'd1;
                end
                     else if (hundredths == 4'd9) begin      
                        hundredths <= 4'd0;
                        tenths <= tenths + 4'd1;
                     end
                        else if (thousandths == 4'd9) begin
                           thousandths <= 4'd0;
                           hundredths <= hundredths + 4'd1;
                        end
                           else begin
                              if (counter == 17'd99999) begin    //0 to 99,999 for .001sec counter
                                 counter <= 17'd0;
                                 thousandths <= thousandths + 4'd1;
                              end
                                 else
                                    counter <= counter + 17'd1;
                           end
                                       
            end
end
         
endmodule

Looks like I'm seeming to favor the 'IF's.
@ Arlet, thanks for the tip of decimal. I think I've learned the bit value is absolute key for proper bit placement. I didn't realize this before, hence my avoiding it and using strictly binary.
@anyone. What's the alternative to all the 'IF's?

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 609 posts ]  Go to page Previous  1 ... 19, 20, 21, 22, 23, 24, 25 ... 41  Next

All times are UTC


Who is online

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