Art and Depression
Mmmohdear....
Thursday, November 21, 2024
Sketchy doodle.
Ah.
Stopped suppressing my creativity. It's terrible but, I'll get back to drawing fit eventually. Hopefully.
Saturday, December 9, 2023
Machine language monitor with BASIC, check!
Pointless, but I had fun, for sure!
What follows is VERY SLIGHTLY self-modifying BASIC code. There's a save routine on rows 2-5, and a bug on row 7, I should remove that. Anyway, the filename after sys command HAS TO be a static string. But.... As long as I change NOTHING on rows 1-2, it is always in a fixed position. So, on row 640 I POKE a little fun out of it.
The default is "ALANGPROGRAM" because it started out as "MLANGPROGRAM" but I had to check which offset was the correct one by poking at it, so now it's an "A".
Self-modifying code is pretty cool and legal.
1 goto10 2 sys57812"alangprogram",8 3 poke193,al-(ha*256):poke194,ha 4 poke174,lo-(hl*256):poke175,hl 5 sys62954 6 print"reset now" 7 poke43,0:poke44,8:poke45,189:poke46,12 10 rem memory monitor and editor 30 i=1:m=0:p=0:s=0 35 print"@<address>,<q>uit":print"return :dump 8" 40 print str$(s);:input a$ 44 if a$="" then goto 400 45 if mid$(a$,i,1)=" " then i=i+1 46 goto 300 50 gosub 150:i=i+1 60 d=b*16 70 gosub 150 80 b=d+b 90 print str$(b)+" "; 95 if p=8 then print "":p=0 96 p=p+1 100 poke s+m, b:m=m+1 110 if i=len(a$) then goto 200 120 i=i+1 140 goto 45 150 rem get octal as decimal 151 b=asc(mid$(a$,i,1)) 160 if b<64 then b=b-48 170 if b>64 then b=b-55 180 return 200 s=s+m: print"" 205 a$="" 210 i=1:m=0:p=1:goto40 220 rem end 300 rem command handlers 310 if a$="q" goto 1000 320 if left$(a$,1)="@" then goto 500 330 if a$="s" then goto 600 390 goto 50 400 rem print 8 byte in hex 401 print chr$(145) + str$(s) +": "; 402 for j=0 to 7: rb=peek(s+j) 410 hi=((240 and rb)/16)+48:lo=(rb and 1 5)+48 420 if hi>57 then hi=hi+7 421 if lo>57 then lo=lo+7 430 print chr$(hi)+chr$(lo)+" "; 440 next j 441 s=s+8:m=0:p=1:i=1:j=0:b=0:d=0 442 print "" 450 goto 40 499 rem memory jump command (@) 500 s=val(mid$(a$,2,len(a$)-1)):i=1:m=0: p=0 505 a$="" 510 goto 40 600 rem save perhaps? 610 input "start memory address:";al 611 input "end memory address:";lo 612 input "filename:";fi$ 620 if fi$="" goto 695 635 ha=int(al/256):hl=int(lo/256) 639 fi$=left$(fi$,12) 640 fori=1tolen(fi$):c=asc(mid$(fi$,i,1) ):poke2048+19+i,c:nexti 690 goto 2 695 i=1:m=0:a$="":goto 40 1000 rem end
Minifying and optimizing this, maybe. In retrospect, you should write your basic WIDE initially, maybe use rem statements to note sections and subroutines. It would make refactoring - including minifying and optimizing - easier.
It would be handy to be able to switch to character and decimal modes, and making use of the default screen editor.
I should probs also write a sprite/tile editor one of these days, but basic IS kinda tedious in some ways. I could write a macroassembler, yes. But on Commodore? In BASIC? unlikely.
But I do want to do that game of some sort. Maybe a roguelike or action roguelike? I also have some further stuff to do on a "text editor". I've had some sort-of working ones, but I can improve them, and they are useful for some stuff... they're also just a skip and a hop away from being a level editor so that's also useful.
I'm also doing some other stuff right now, ended up writing a sort of an experimental macroparser thingy, with the help of a LLM today.
Wednesday, October 25, 2023
This was a while back. Minidium from C=1/87
I typed in a listing, successfully, and I sorta understood what was going on.
Here's a link to the magazine it's from: https://archive.org/details/C-Lehti-1987-1/mode/2up
Again, trauma therapy. Never successfully wrote a working program from a listing as a child; Certainly not one with a bunch of machine language hex dump in it.
Monday, June 1, 2020
Trying to get back to doing some art
Not much to say, really. I'm doodling some on a notebook, and also looking at stuff like Krita and OpenToonz for animation. Either is sufficient, if not overkill, and, well, it's going to be a bunch of crappy doodles for a good long while,. but my main goal is to enjoy the process right now.
Sunday, March 18, 2018
Cursor Control with Commodore 64.
The ability to draw a character at any spot on the screen - within the constraint of rows and columns, perhaps, is key, when you're trying to create either a text editor, or a roguelike, or nearly anything with a text-based UI.
It's apparently also impossible on the Apple I, but fortunately I'm working with something a bit more advanced. I'm not doing THAT retro.
C64 Programmer's Reference Guide is fairly good. I'm not entirely sure I could have comprehended it, or would have had access to it when I was in grade school, but it's at least theoretically possible.
I definitely would have been able to get this book, whether via a library or by pestering my parents sufficiently. Not sure I had the character and audacity required for such a proactive behavior, though, but meh.
In any case, the various bits of secret sauce I've discovered thus far are:
poke 214, row
poke 211, column:sys (58732)
This sets the cursor to a specific row and column, as far as printing is considered. The SYS is required to set the row and column.
The get loop is fairly common, being
You can find that in many different sources. However, it does not display the cursor. Poking at the right spot (204, 0 for enable, 1 for disable) does turn the cursor on and off, but for some reason, the cursor location is wrong.get a$:if a$="" then goto
You can also do direct manipulation of screen memory by poking at locations from 1024 onwards, but unfortunately the character ROM doesn't directly map to PETSCII.
As a downside of using GET input, you do not get to benefit from the, actually rather nifty on-screen editing that is default for C64.
I'm trying to create a status line, by jumping between cursor location and line 23, where I print current cursor location and... well, haven't really thought that far. Filename, I suppose. Currently I'm just putting the last key's code there.
I flip editor mode on F1, of course the only command currently supported is "save", and frankly, there is no scrolling, so max document length is 25 lines, but, baby steps.
print#, which is used to write to files, is also... finicky, I guess. it uses slightly different printing rules, and it differentiates between variables by CRs (char code 13), which makes it unsuited to printing numbers, unless you use some sort of string encoding. I did figure out I could save ASM files as hex strings, and loading those would be quite simple. I might use that as an intermediate step.
Anyway, the various SYS commands are fortunately documented in the Programmer's Reference Guide.
I am currently working with the idea that actual data is kept on known area in memory, which is then written to disk. I've already run into some issues with the memory area not being cleared, which ended up with this little bit of... fun.
a900a2009d00109dff109dff119dff12e8e0ffd0ef60To break it down:
a900 lda 0 a200 ldx 0 9d0010 sta 4096,x 9dff10 sta 4351,x 9dff11 sta 4606,x 9dff12 sta 4861,x e8 inx e0ff cpx 255 d0ef bne -16 60 rts
It's really moderately straight-forward, it should zero an area from 4096 to 5116, or so, by copying accumulator to various memory slots adjusted by x-index. it increments x-index by 1, then compares it to 255, and if it's not there yet, it jumps back 16 bytes in execution.
Biggest new thing I learned was that the comparison operator jumps backwards or forwards by a specific number of bytes. Makes sense.
Oh, I guess I should mention I tested this by using this little program here :
ready. list 10 rem hex8todec 30 i=1:m=0 35 input "mem address start:";s 40 print str$(s);:input a$ 50 gosub 150:i=i+1 60 d=b*16 70 gosub 150 80 b=d+b 90 print b,; 100 poke s+m, b:m=m+1 110 if i=len(a$) then goto 200 120 i=i+1 140 goto 50 150 b=asc(mid$(a$,i,1)) 160 if b<64 then b=b-48 170 if b>64 then b=b-55 180 return 200 rem end ready.
There are a couple of different ways of doing byte to hex conversion and vice versa.
A lookup table works fine, and is pretty concise for byte-to-hex, since the and masking and division need to be done anyway. I don't worry much about the memory limitations at this point, although they are a concern with real-world applications. My editor program is starting to reach the point where putting the screen at 4096 may risk overwriting the actual code.
For hex-to-byte conversion, I guess you could create an array of integers of the PETSCII codes, and compare each letter to the array, recording the index of the match, but I'm not convinced it's faster than what I have here. Might use less memory, though.
Labels:
assembly,
Commodore 64,
programming,
retro
Wednesday, March 14, 2018
A Simple Quiz Game in Commodore 64 Basic a Grade Schooler Could Write
10 print "quizgame"
20 open 1,8,8,"quizfile,r,s"
30 dim answer$(9)
35 i=0
36 p=0:rem points
37 qs$=""
40 input# 1,a$
50 rem print a$
60 if a$="!" goto 900
80 ca=0:rem correct answers
100 type$=left$(a$,1)
130 if type$="q" then qs$=qs$+mid$(a$,2,255)
150 if type$="a" then gosub 200
160 if type$="c" then gosub 250
190 goto 40
200 answer$(i)=mid$(a$,2,255)
210 i=i+1
220 return
250 rem gosub from 160
260 ca=val(mid$(a$,2,1))
270 gosub 300
280 return
300 print qs$
310 for j=0 to i-1:rem gameplay
320 print str$(j+1)+":"+answer$(j)
330 next j
340 i=0
350 get an$:if an$="" goto 350
360 an=val(an$)
370 if ca=an then p=p+1
380 print "your answer was:", an
390 print "correct answer was:",ca
400 print ,answer$(ca-1)
410 return
900 close 1
910 print "number of points:"+str$(p)
20 open 1,8,8,"quizfile,r,s"
30 dim answer$(9)
35 i=0
36 p=0:rem points
37 qs$=""
40 input# 1,a$
50 rem print a$
60 if a$="!" goto 900
80 ca=0:rem correct answers
100 type$=left$(a$,1)
130 if type$="q" then qs$=qs$+mid$(a$,2,255)
150 if type$="a" then gosub 200
160 if type$="c" then gosub 250
190 goto 40
200 answer$(i)=mid$(a$,2,255)
210 i=i+1
220 return
250 rem gosub from 160
260 ca=val(mid$(a$,2,1))
270 gosub 300
280 return
300 print qs$
310 for j=0 to i-1:rem gameplay
320 print str$(j+1)+":"+answer$(j)
330 next j
340 i=0
350 get an$:if an$="" goto 350
360 an=val(an$)
370 if ca=an then p=p+1
380 print "your answer was:", an
390 print "correct answer was:",ca
400 print ,answer$(ca-1)
410 return
900 close 1
910 print "number of points:"+str$(p)
So...yeah.
Basically, that's all it took. It reads in a file "quizfile" and lines that start with a q, are part of the question, a lines contain an answer, and c lines are followed by a number indicating which answer was correct.
For an example:
qWhat is your favourite color
aBlue
aRed
aBlue, i mean red!
c1
This is not quite enough, as the ability to create the file is required. A simple solution - and the one I used to write the file was this:
5 dim o$(100)
6 i=1
10 input o$(i)
20 if o$(i)="!" then 100
40 i=i+1
50 goto 10
100 print "end"
105 print i;"lines of text"
107 open 1,8,8,"@0:quizfile,w,s"
110 for j=0 to i
120 print o$(j)
140 print#1,o$(j)
150 next
160 close 1
6 i=1
10 input o$(i)
20 if o$(i)="!" then 100
40 i=i+1
50 goto 10
100 print "end"
105 print i;"lines of text"
107 open 1,8,8,"@0:quizfile,w,s"
110 for j=0 to i
120 print o$(j)
140 print#1,o$(j)
150 next
160 close 1
It's not good enough, though, since you do need the ability to add new questions.
It's also not the simplest possible way, since you could do the whole thing with a goto after the open in a input-print# loop until end symbol, but I often putter around, trying different things, and sometimes the solution can be messy.
simple would be something like this:
10 open 1,8,8,"@0:quizfile,w,s"
20 input a$
30 if a$="!" then 100
40 print# 1,a$
50 goto 20
100 close 1
20 input a$
30 if a$="!" then 100
40 print# 1,a$
50 goto 20
100 close 1
Well, I'm going to be compassionate towards my younger self. After all, it took me a while to figure out how to write and load from files, and an arcane syntax like "@0:" is more than a bit odd, although I think it means "start writing to the file from this location. Because, otherwise, the file doesn't save, and then, sadness.
Tuesday, March 13, 2018
Adventures in Commodore 64 Basic
Let me try to get this formatted nicely in HTML:
Here's the stylings:
To tell the truth, I've already written a bunch of tiny practice programs.
10 rem decimal to hex byte converter 20 rem need some data, use basicmem 30 begin=4096 40 finish=4128 50 for i=begin to finish 60 v=peek(i) 65 rem numbers start at 48=0 70 hi=int(v/16):lo=v and 15 75 rem numbers start at 48=0 80 lo$=chr$(48+lo) 90 hi$=chr$(48+hi) 100 rem chars start at 65=a 110 if lo>9 then lo$=chr$(55+lo) 120 if hi>9 then hi$=chr$(55+hi) 130 print hi$lo$+" "; 140 cols=cols+1 150 if cols=8 then gosub 200 160 next 170 goto 230 200 print ";" 210 cols=0 220 return 230 rem end
Here's the stylings:
div.commodore { border: 60px solid #0088ff; color: #0088ff; background-color: #0000aa; text-transform: uppercase; font-family: "Courier", "Courier New"; }
To tell the truth, I've already written a bunch of tiny practice programs.
- One that takes in input lines and writes them to file,
- Read lines from file
- change the cursor, border and background color - in machine language, put into memory. That was the image in the last post.
- one that tests the hires mode. Things get interesting there
and a few others. However, today I wrote something potentially useful - a bit of code that dumps an area from memory to the screen in hex. Doing that is probably going to be useful, once I get into more machine language stuff, especially as I cannot pretend to own a TASM cartridge or something.
Well.
What I wrote is a START, as, since it being a basic program, it's slow, AND unless I combine it with an interface to edit memory, it doesn't do that much - I can do poke-run loops, but that seems remarkably tedious.
An alternate way would be to translate this to ASM, then load it to an area in memory, and then activate it via SYS calls.
Still, the output looks cool.
The program dumped is, naturally, the screen-color altering one from my previous post.
A9 is a single-byte LDA, 8D is STA followed by a 2-byte little endian address, 60 is RTS.
I suppose a sys calls is basically just a JSR, then.
Still, the output looks cool.
The program dumped is, naturally, the screen-color altering one from my previous post.
A9 is a single-byte LDA, 8D is STA followed by a 2-byte little endian address, 60 is RTS.
I suppose a sys calls is basically just a JSR, then.
Subscribe to:
Posts (Atom)