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
So, what's left?
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
get a$:if a$="" then goto
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.

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.
a900a2009d00109dff109dff119dff12e8e0ffd0ef60
 To 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.

Running the program with an appropriate sys address call, of course.
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.

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)

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

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

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:



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.

  1. One that takes in input lines and writes them to file, 
  2. Read lines from file
  3. change the cursor, border and background color - in machine language, put into memory. That was the image in the last post. 
  4. 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.

Monday, March 12, 2018

Fixing My Childhood Trauma With Commodore 64

Holy Belldandy's Eyebrows, Batman!



Yes, I possessed one of these wonderful machines, wayback. I was even interested in programming with them. Unfortunately, very little materials were available, outside a fairly good computer magazine, and my understanding was really quite poor.

At some point in grade school - between age 9 and 12,  I was quite into it - even if I had tried to trade my C64 for an MSX, because it had direct commands for graphics and sound. However, typing in program listings rarely worked and I really couldn't debug the programs - didn't even know how.  I did try to write a trivial pursuit type question-answers game in the fifth grade, but it was just this awful mess of IF-THENs. I think I tried using DATA statements, but I couldn't quite get it to work, so I gave up on that, and the fact I even remember that, should tell you something.

At that age, I didn't have any money. I couldn't buy ANYTHING, although I did get my parents to buy, and later on had a subscription to the C=magazine. I also think I had ONE book (ISBN 951-832-005-5), but it seems to have vanished at some point. :/

So, as a project, I'm doing some C64 programming, with the following constraints:
- All code is written inside the emulator
- No pre-existing applications are allowed. I don't know if I had any
- I will allow for the internet, which is a bit of a cheat, admittedly, but there are chances I could have gleaned the information from a magazine.

My goals are, roughly:
 - A text editor,
 - A hex editor, capable of writing to disk, for some rough machine code working
 - MAYBE a macroassembler.
 - Various audio/video tests
 - The !"#%¤%& game, it's engine and enough demo questions for a proof of concept.

Since I'm bringing in a generation's worth of computer science knowhow, I can say that the quiz program needs to load the questions from a file on a floppy disk (or perhaps a datassette, too) instead of being hardcoded, and the questions need to be editable with (a, the) text editor.

I do hope to document this, since a "How do I Basic to Macroassembler" does not seem to exist in the 'net at this point.