WIP: Jeff's character editor

Basic and Machine Language

Moderator: Moderators

User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

WIP: Jeff's character editor

Post by Jeff-20 »

I had been using the same old character editor I made in 1994. I decided to upgrade it. This is not a "release" because it's very much tailored to my needs, and it's completely BASIC and joystick controlled.

I'm posting this because it would like some advice on how to make it better. Did I miss any useful commands? Can it be crunched or made faster? I want it to stay basic so I can make quick project-specific changes. Also must stay unexpanded.

Here's a DOWNLOAD and screenshot:

Image

It had loads of features. I added a string tip as suggested by Mike to improve the speed of drawing the screen.

Current Limitations:
For memory limitations, I made vertical and horizontal scrolling 1 directional. I am ok with this, but if there's a simple, efficient way to have both directions, that would be great.

I would like to improve the R90 and SPN commands for speed. Each take about 3 seconds to complete. Is there a faster way?

R90 - rotate character 90 degrees. (cannot be undone because of memory limits)

Code: Select all

46 POKEU,124:J=128:FORI=.TO7:A(I)=.:Y=128:FORT=.TO7:L=PEEK(7-T+V+8*X)

47 A(I)=A(I)+Y*-((LANDJ)=J):Y=Y/2:NEXT:J=J/2:NEXT:FORT=.TO7:POKET+V+8*X,A(T):NEXT:GOTO35
SPN - spins the character for mirror image.

Code: Select all

48 GOSUB58:FORT=.TO7:J=128:Y=.:FORI=.TO7:Y=Y-2^I*((A(T)ANDJ)=J):J=J/2:NEXT:POKEL+T,Y:NEXT:GOTO35
Below I'll add a list of commands that are not obvious:

ALL - Shift A clears characters. You should do this to start.
Cursor Keys - browse character set (the up/down key moves the selector left, the left/right key moves the selector right, Shift/C=/CRTL allow you to skip characters for faster selection)
1DB - puts selected character on drawing board 1, joystick editable
2DB - puts selected character on drawing board 2, this is for holding a character outside of memory for comparison or maintain an original before editing
F1C - changes character color. Hold Shift to use Multicolor mode.
ENT - enter data for current line
UND - undo changes, only works when character is selected.
PLY - treats data as music notes (something I often do in games)
SWP - swaps character on drawing board with browser
OVW - toggles overwrite and replace mode for drawing board
EXT - gives you the option to save the set for future editing. Just edit and enter the given line.
High Scores, Links, and Jeff's Basic Games page.
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

I'm looking at KingTrode's editor. Would it be easy to add an ML routine to spin or rotate the character? It would be faster, but maybe not memory efficient.

I feel like there are some obvious commands I am missing...
High Scores, Links, and Jeff's Basic Games page.
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Post by KingTrode »

Jeff-20 wrote:I'm looking at KingTrode's editor. Would it be easy to add an ML routine to spin or rotate the character? It would be faster, but maybe not memory efficient.

I feel like there are some obvious commands I am missing...
Hi Jeff

Here is the assembler routine from my CharEdit program:-

Code: Select all

; *********************
; * Rotate 90 Degrees *
; *********************
rotate
				LDY		#7
				LDA		#0
rotate_00									; Zero the 8 bytes used for temp storage
				STA		matrix_temp,Y
				DEY
				BPL		rotate_00	
				
				LDY		#7
rotate_01									; Process the 8 bytes in a loop
				LDA		matrix,Y
				JSR		rotate_03			; Jump to subroutine to process the 8 bits 
				DEY
				BPL		rotate_01
				
				LDX		#7
rotate_02									; Copy the 8 bytes of rotated character into character matrix
				LDA		matrix_temp,X
				STA		matrix,X
				DEX
				BPL		rotate_02
				
				RTS

rotate_03									; Process the 8 bits in a loop
				LDX		#0
rotate_04
				CLC
				ASL
				PHA
				LDA		matrix_temp,X
rotate_05
				ROL
				STA		matrix_temp,X
				PLA
				INX
				CPX		#8
				BNE		rotate_04
				RTS
matrix = pointer to the 8 bytes used for the character in the edit grid.
matrix_temp = pointer to 8 bytes of temporary storage.

I have no idea how much RAM your basic routine takes up, when assembled this routine takes 52 bytes of RAM for the code part and is obviously considerably faster.

If your not using the tape buffer then routine and temp storage could go there along with a few other routines to speed things up.

I'm sure Mike or someone else could improve/crunch the code some more.

PS: I've not been posting much lately or doing much on the VIC front as I have been very busy with other things, so I thought I would take this opportunity to make a post just to let you all know I'm still around and read the forums most days.
User avatar
Mike
Herr VC
Posts: 4845
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

KingTrode wrote:... I'm sure Mike ...
8)

I quickly hacked this into the VICE monitor:

Code: Select all

.C:02A1   A0 07      LDY #$07
.C:02A3   B1 FB      LDA ($FB),Y
.C:02A5   A2 07      LDX #$07
.C:02A7   6A         ROR A
.C:02A8   3E F8 02   ROL $02F8,X
.C:02AB   CA         DEX
.C:02AC   10 F9      BPL $02A7
.C:02AE   88         DEY
.C:02AF   10 F2      BPL $02A3
.C:02B1   A0 07      LDY #$07
.C:02B3   B9 F8 02   LDA $02F8,Y
.C:02B6   91 FB      STA ($FB),Y
.C:02B8   88         DEY
.C:02B9   10 F8      BPL $02B3
.C:02BB   60         RTS
27 Bytes. ;)

251/252 point to the character to be rotated. $02F8 .. $02FF are used as scratch-pad.

This will turn the character clockwise. To turn the character counter-clockwise, change 'ROR A:ROL $02F8,X' to 'ROL A:ROR $02F8,X'
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Re: WIP: Jeff's character editor

Post by Jeff-20 »

Jeff-20 wrote:I want it to stay basic so I can make quick project-specific changes. Also must stay unexpanded.
I'm interested in figuring out how to do this quickly in basic. Could you look at the BASIC code above? I don't think I really have the room for SYS routines.
High Scores, Links, and Jeff's Basic Games page.
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Updates:
- changed screen layout to group similar commands
- browser also shows ROM character (to keep track of position)
- music player now gives visual of what note is being read (line drawn)
- multicolor mode added to onscreen commands
- full data entry mode (via shift return)

Immediate problems:
- spin and rotate BASIC routines are slow, need to be optimized
- data entry mode can be disrupted by cursor keys
- browser can skip characters (via shift or C=) only when moving right, not left
- vertical and horizontal scroll only moves single direction
- very little memory for adding features, needs further crunching
High Scores, Links, and Jeff's Basic Games page.
User avatar
Mike
Herr VC
Posts: 4845
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Hi, Jeff,
Jeff-20 wrote:I don't think I really have the room for SYS routines.
Please take a look at gr2.prg.
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

You guys keep pushing me to ML when you know it frightens me. :lol:

Ok, what just happened here? I need explication for lines 0, 1 and 46.
Poke 55, 0? Also, I notice you removed poke 47 and poke 48. Are those unnecessary? I've been doing it so long that i never questioned it.

Also, does this mean what I did is as fast as it can get in basic?
High Scores, Links, and Jeff's Basic Games page.
User avatar
Mike
Herr VC
Posts: 4845
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Jeff-20 wrote:You guys keep pushing me to ML when you know it frightens me. :lol:
;)
Ok, what just happened here? I need explication for lines 0, 1 and 46.
Line 0 contains the ML code I wrote in the preceding post. Originally it looked like this:

Code: Select all

0 REMZZZZZZZZZZZZZZZZZZZZZZZZZZZ
(27 Z's). I then "injected" the code with the VICE monitor. Only one small caveat: code put into a REM line this way must not contain any zeroes.

Code: Select all

1 POKE55,0:POKE56,28:POKE45,75:POKE46,26:CLR:POKE657,128:GOTO60
Poke 55, 0?
The two addresses 55/56 point to the top of BASIC memory. If you only set address 56, the other address 55 (the low byte) still could contain an value between 1..255, thus not lowering the roof to address 7168 as intended.
Also, I notice you removed poke 47 and poke 48. Are those unnecessary?
The pointer at 47/48 points to the start of arrays, 51/52 point to the bottom of string space. Both are being taken care of by the CLR command, provided 45/46, and 55/56 have been set correctly beforehand.

Code: Select all

46 POKEU,124:QQ=V+8*X:POKE252,QQ/256:POKE251,QQ-256*PEEK(252):SYS4102:GOTO35
As in the original, POKEU,124 temporarily replaces the character with a checkerboard pattern, I left that in. QQ contains the address of the character in RAM, and is split into the low-, and high-byte with the two POKEs into 251, 252 - they indicate to the ML routine called with SYS4102, which character should be rotated.
Also, does this mean what I did is as fast as it can get in basic?
Edit: I tried with the following re-implementation:

Code: Select all

1 POKE55,0:POKE56,28:CLR
2 FORT=0TO7:POKE7168+T,PEEK(32768+T):NEXT
3 POKE7680,0:POKE38400,0:POKE36869,255
4 T1=TI:AD=7168
5 FORX=0TO7:A(X)=.:NEXT
6 FORY=0TO7:A=PEEK(AD+Y):FORX=0TO7:A(X)=A(X)/2+(AAND128):A=A+A:NEXT:NEXT
7 FORY=0TO7:POKEAD+Y,A(Y):NEXT:T2=TI
8 GETA$:IFA$=""THEN8
9 POKE36869,240:PRINT(T2-T1)/60
... which needs ~1.1 seconds.
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Wow. That's more than twice as fast and smaller! It took me a while to really understand how it worked.

Similarly, how could my mirror routine be improved? It's even slower!

Code: Select all

48 GOSUB58:FORT=.TO7:J=128:Y=.:FORI=.TO7:Y=Y-2^I*((A(T)ANDJ)=J):J=J/2:NEXT:POKEL+T,Y:NEXT:GOTO35 
On the topic of 45/46, I feel very misled by the reference guide. Page 82 to 85 insist that I need to change location 52 and 56. I would see this in many programs made during the time. Now that I look at a memory map, I see you're right. But, can I be safe to assume PEEK(55)=0 when a program is started in unexpanded memory? It would save me 6 bytes to do so. :D
High Scores, Links, and Jeff's Basic Games page.
User avatar
Mike
Herr VC
Posts: 4845
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

What kills your routine is the power operation (2^...). That is very slow.

The mirroring could be improved with a very similar routine to the one I gave above for rotating a character, if you don't want to use a table:

Code: Select all

1 POKE55,0:POKE56,28:CLR 
2 FORT=0TO7:POKE7168+T,PEEK(32768+T):NEXT 
3 POKE7680,0:POKE38400,0:POKE36869,255 
4 T1=TI:AD=7168 
5 FORY=0TO7:A=PEEK(AD+Y):B=.:FORX=0TO7:B=B/2+(AAND128):A=A+A:NEXT:POKEAD+Y,B:NEXT:T2=TI
6 GETA$:IFA$=""THEN6 
7 POKE36869,240:PRINT(T2-T1)/60
... doing its job in ~0.8 seconds.
But, can I be safe to assume PEEK(55)=0 when a program is started in unexpanded memory?
Only if your program is the first to be run after reset.

And a prominent counter-example happens with Super-Expander inserted in the expansion port.
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Awesome!
Mike wrote:What kills your routine is the power operation (2^...). That is very slow.
I use it in line 41 to draw the bit. Is there any way to get around that?

Code: Select all

41 T=V+8*X+B:I=2^(7-A):D=247-D:POKES+6,P+14*(D=123):IFD=123ORQTHENPOKET,PEEK(T)ORI:D=123
High Scores, Links, and Jeff's Basic Games page.
User avatar
Mike
Herr VC
Posts: 4845
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Jeff-20 wrote:Awesome!
;)
I use it in line 41 to draw the bit. Is there any way to get around that?
You can replace 'I=2^(7-A)' with 'I=PEEK(33384+A)'. (<- this accesses the definition of the descending diagonal line in the character ROM, and is also used by MINIGRAFIK. :mrgreen:)
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Clever! :lol:

Do you know if there's a way to confirm where my PEEK(45) should be? I think I got lost somewhere. I'm scanning memory, but I can't tell exactly where the program ends. Does it end with the last command or should there be extra data after that?
High Scores, Links, and Jeff's Basic Games page.
User avatar
Mike
Herr VC
Posts: 4845
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Jeff-20 wrote:Do you know if there's a way to confirm where my PEEK(45) should be?
A BASIC program ends with three 0-bytes, and 45/46 point to the immediately following address.

The easiest way to re-establish a correct value for 45/46 would be an OLD routine, like this one.

You'd then correct the POKEs to 45 and 46 in line 1 from the PEEK()'d values, being careful not to change the program length again.
Post Reply