Videopac / Odyssey2 forum

Programming the Videopac / Odyssey2 => Programming => Topic started by: gertk on April 20, 2011, 10:28:03 PM



Title: C7420 basic stuff
Post by: gertk on April 20, 2011, 10:28:03 PM
Just finished my simple 'basic decoder' for *.bas files generated by the mbed C7420 emulator so I can read them on the PC.
Input is a .bas file which has been stored on the micro-sd card, output is the readable (ASCII) version.
The .bas files of the emulator are regular C7420 tape files without the lead-in and filler bytes. (24 bytes header, 1 byte zero and then the program data)

This is some doodling I did (trying to port space invaders to C7420 basic) All the SETET lines are pre-calculated by another program which used the original space invaders rom file as bitmap source... The program is far from finished, lots of the subroutines need to be filled in and it is way too slow now but it shows what can be done with the 'sort-of-bitmap' graphics of the 7400, the invaders move horizontally in 2 pixel steps (!) Sorry about the cryptic variable names but C7420 Basic only uses the first two characters of each variable name.

Code:
00005 CLEAR 1000
00010 GOSUB 1000
00020 GOSUB 10000
00030 DIM IN(11*5)
00040 CX=0:CY=4:IU=0:CI=5*11-1
00050 IX=20:IY=14:XD=-1:YD=0:ID=0
00060 RG=1
00070 GOSUB 4200
00080 GOSUB 4300
00090 GOSUB 4700
00100 GOSUB 4400
00110 GOSUB 5200
00115 GOSUB 5000
00150 GOSUB 6100
00900 GOTO 110
00998 DISPLAY
00999 END
01000 REM init screen
01010 INIT 0
01020 ET 7,0,0
01030 STORE
01040 RETURN
04000 REM show current invader
04010 IF EF THEN GOSUB 4100:RETURN
04020 IF IN(CI)=0 THEN 4050
04030 GOSUB 5000
04050 IU=0
04060 RETURN
04100 REM countdouwn invader explosion
04110 RETURN
04200 REM init bunkers
04299 RETURN
04300 REM init invader array
04310 FOR T=0 TO 10
04315 FOR S=0 TO 4
04320 IN(S*11+T)=1
04325 NEXT S
04330 NEXT T
04399 RETURN
04400 REM clear center of screen
04410 FOR Y=1 TO 17
04420 FOR X=0 TO 39
04430 CURSORX X:CURSORY Y:PRINTCHR$(32);
04440 NEXT X
04450 NEXT Y
04499 RETURN
04500 REM show score
04599 RETURN
04600 REM show bunkers
04699 RETURN
04700 REM draw baseline
04799 RETURN
05000 REM place invader n at pos x,y
05010 SX=1+INT(CX/4):SY=23-CY
05020 OF=(CX AND 3)+IT
05030 CURSORX SX
05040 CURSORY SY
05050 PRINT IN$(OF);
05052 CURSORX SX:CURSORY SY-1
05054 PRINT"   ";
05070 LINE SY-1,SY
05080 RETURN
05200 REM increment current invader
05210 CI=CI+1
05230 IF CI<55 THEN 5300
05240 CI=0
05250 IF FL THEN FL=0:GOTO 5270
05260 FL=12
05270 IY=IY+YD:YD=0
05280 IX=IX+XD
05290 GOTO 5400
05300 IF IN(CI)=0 THEN 5210
05400 CX=CI-11*INT(CI/11)
05410 CX=CX*12+IX
05420 A=INT(CI/11)
05430 CY=A+A+IY
05450 IF CY<5 THEN EF=1:RETURN
05460 IT=INT(CI/22)*4+FL
05500 RETURN
06000 REM check button/stick
06099 RETURN
06100 REM check limits
06102 LF=0
06105 IF ID THEN 6150
06110 SA=-32758+80
06115 FOR Y=1 TO 17
06120 IF PEEK(SA)<>160 THEN LF=1
06122 SA=SA+80
06125 NEXT Y
06130 IF LF THEN XD=1:ID=1:YD=-1
06140 RETURN
06150 SA=-32682+80
06155 FORY=1 TO 17
06160 IF PEEK(SA)<>160 THEN LF=1
06162 SA=SA+80
06165 NEXT Y
06170 IF LF THEN XD=-1:ID=0:YD=-1
06180 RETURN
06199 RETURN
06200 REM count invaders
06210 C=0
06220 FOR N=0 TO 54
06230 IF IN(N) THEN C=C+1
06240 NEXT N
06250 IR=C
06299 RETURN
06300 REM add score
06399 RETURN
06400 REM test bullet
06499 RETURN
10000 DIM IN$(24)
10001 SETET 32,"00000000000000000000"
10002 REM invader type 0,0
10005 SETET 33,"00031f3f393f060d3000"
10010 SETET 34,"00c0f8fc9cfc60b00c00"
10030 SETET 35,"0000070f0e0f01030c00"
10040 SETET 36,"00f0feff67ff986c0300"
10060 SETET 37,"00000103030300000300"
10070 SETET 38,"003cffff99ff66db0000"
10080 SETET 39,"000080c0c0c00000c000"
10100 SETET 40,"000f7fffe6ff1936c000"
10110 SETET 41,"0000e0f070f080c03000"
11000 IN$(0)=CHR$(33)+CHR$(34)+CHR$(32)
11010 IN$(1)=CHR$(35)+CHR$(36)+CHR$(32)
11020 IN$(2)=CHR$(37)+CHR$(38)+CHR$(39)
11030 IN$(3)=CHR$(32)+CHR$(40)+CHR$(41)
12000 REM invader type 1,0
12005 SETET 42,"000412171d1f0f040800"
12010 SETET 43,"001024f4dcfcf8100800"
12020 SETET 44,"00010405070703010200"
12030 SETET 45,"000489fd77fffe040200"
12050 SETET 46,"00000101010100000000"
12060 SETET 47,"0041227fddffff418000"
12070 SETET 48,"00004040c0c080008000"
12080 SETET 49,"0010485f777f3f102000"
12090 SETET 50,"004090d070f0e0402000"
13000 IN$(4)=CHR$(42)+CHR$(43)+CHR$(32)
13010 IN$(5)=CHR$(44)+CHR$(45)+CHR$(32)
13020 IN$(6)=CHR$(46)+CHR$(47)+CHR$(48)
13030 IN$(7)=CHR$(32)+CHR$(49)+CHR$(50)
14000 REM invader type 2,0
14010 SETET 51,"000103070d0f02050a00"
14020 SETET 52,"0080c0e0b0f040a05000"
14030 SETET 53,"00000001030300010200"
14040 SETET 54,"0060f0f86cfc90689400"
14070 SETET 55,"00183c7edbff245aa500"
14090 SETET 56,"00060f1f363f09162900"
14100 SETET 57,"00000080c0c000804000"
15000 IN$(8)=CHR$(51)+CHR$(52)+CHR$(32)
15010 IN$(9)=CHR$(53)+CHR$(54)+CHR$(32)
15020 IN$(10)=CHR$(32)+CHR$(55)+CHR$(32)
15030 IN$(11)=CHR$(32)+CHR$(56)+CHR$(57)
20000 REM invader type 0,1
20010 SETET 58,"00031f3f393f0e190c00"
20020 SETET 59,"00c0f8fc9cfc70983000"
20030 SETET 60,"0000070f0e0f03060300"
20040 SETET 61,"00f0feff67ff9c660c00"
20060 SETET 62,"00000103030300010000"
20070 SETET 63,"003cffff99ffe799c300"
20080 SETET 64,"000080c0c0c000800000"
20090 SETET 65,"000f7fffe6ff39663000"
20100 SETET 66,"0000e0f070f0c060c000"
21000 IN$(12)=CHR$(58)+CHR$(59)+CHR$(32)
21010 IN$(13)=CHR$(60)+CHR$(61)+CHR$(32)
21020 IN$(14)=CHR$(62)+CHR$(63)+CHR$(64)
21030 IN$(15)=CHR$(32)+CHR$(65)+CHR$(66)
22000 REM invader type 1,1
22010 SETET 67,"000402070d1f17140300"
22020 SETET 68,"001020f0d8fcf4146000"
22030 SETET 69,"00010001030705050000"
22040 SETET 70,"000488fc76fffd05d800"
22060 SETET 71,"00000000000101010000"
22070 SETET 72,"0041227fddff7f413600"
22080 SETET 73,"0000000080c040400000"
22090 SETET 74,"0010081f377f5f500d00"
22100 SETET 75,"004080c060f0d0508000"
23000 IN$(16)=CHR$(67)+CHR$(68)+CHR$(32)
23010 IN$(17)=CHR$(69)+CHR$(70)+CHR$(32)
23020 IN$(18)=CHR$(71)+CHR$(72)+CHR$(73)
23030 IN$(19)=CHR$(32)+CHR$(74)+CHR$(75)
24000 REM invader type 2,1
24010 SETET 76,"000103070d0f05080400"
24020 SETET 77,"0080c0e0b0f0a0102000"
24030 SETET 78,"00000001030301020100"
24040 SETET 79,"0060f0f86cfc68040800"
24070 SETET 80,"00183c7edbff5a814200"
24090 SETET 81,"00060f1f363f16201000"
24100 SETET 82,"00000080c0c080408000"
25000 IN$(20)=CHR$(76)+CHR$(77)+CHR$(32)
25010 IN$(21)=CHR$(78)+CHR$(79)+CHR$(32)
25020 IN$(22)=CHR$(32)+CHR$(80)+CHR$(32)
25030 IN$(23)=CHR$(32)+CHR$(81)+CHR$(82)
25040 RETURN
30000 INIT 7:END


Title: Re: C7420 basic stuff
Post by: gertk on April 20, 2011, 10:32:26 PM
Oh, and this is the decoder/interpreter

Code:
//  Videopac basic file decoder (*.bas)
//  for basic programs saved by the mbed c7420 emulator
//  by Gert van der Knokke 20-04-2011

#include <stdio.h>

void decode(token)
{
switch(token)
{
case 0x04:printf("$");break;
case 0x80:printf("END");break;
case 0x81:printf("FOR"); break;
case 0x82:printf("NEXT");break;
case 0x83:printf("DATA");break;
case 0x84:printf("INPUT");break;
case 0x85:printf("DIM");break;
case 0x86:printf("READ");break;
case 0x87:printf("LET");break;
case 0x88:printf("GOTO");break;
case 0x89:printf("RUN");break;
case 0x8a:printf("IF");break;
case 0x8b:printf("RESTORE");break;
case 0x8c:printf("GOSUB");break;
case 0x8d:printf("RETURN");break;
case 0x8e:printf("REM");break;
case 0x8f:printf("STOP");break;
case 0x90:printf("ON");break;
case 0x91:printf("LPRINT");break;
case 0x92:printf("DEF");break;
case 0x93:printf("POKE");break;
case 0x94:printf("PRINT");break;
case 0x95:printf("CONT");break;
case 0x96:printf("LIST");break;
case 0x97:printf("LLIST");break;
case 0x98:printf("CLEAR");break;
case 0x99:printf("CLOAD");break;
case 0x9a:printf("CSAVE");break;
case 0x9b:printf("TX");break;
case 0x9c:printf("GR");break;
case 0x9d:printf("SCREEN");break;
case 0x9e:printf("LINE");break;
case 0x9f:printf("DISPLAY");break;
case 0xa0:printf("STORE");break;
case 0xa1:printf("INIT");break;
case 0xa2:printf("CURSORX");break;
case 0xa3:printf("CURSORY");break;
case 0xa4:printf("SCROLL");break;
case 0xa5:printf("PAGE");break;
case 0xa6:printf("BRIGHT");break;
case 0xa7:printf("SOUND");break;
case 0xa8:printf("DELIM");break;
case 0xa9:printf("SETET");break;
case 0xaa:printf("SETEG");break;
case 0xab:printf("ET");break;
case 0xac:printf("EG");break;
case 0xad:printf("NEW");break;
case 0xae:printf("TAB(");break;
case 0xaf:printf("TO");break;
case 0xb0:printf("FN");break;
case 0xb1:printf("SPC(");break;
case 0xb2:printf("THEN");break;
case 0xb3:printf("NOT");break;
case 0xb4:printf("STEP");break;
case 0xb5:printf("+");break;
case 0xb6:printf("-");break;
case 0xb7:printf("*");break;
case 0xb8:printf("/");break;
case 0xb9:printf("^");break;
case 0xba:printf("AND");break;
case 0xbb:printf("OR");break;
case 0xbc:printf(">");break;
case 0xbd:printf("=");break;
case 0xbe:printf("<");break;
case 0xbf:printf("SGN");break;
case 0xc0:printf("INT");break;
case 0xc1:printf("ABS");break;
case 0xc2:printf("USR");break;
case 0xc3:printf("FRE");break;
case 0xc4:printf("LPOS");break;
case 0xc5:printf("POS");break;
case 0xc6:printf("SQR");break;
case 0xc7:printf("RND");break;
case 0xc8:printf("LOG");break;
case 0xc9:printf("EXP");break;
case 0xca:printf("COS");break;
case 0xcb:printf("SIN");break;
case 0xcc:printf("TAN");break;
case 0xcd:printf("ATN");break;
case 0xce:printf("PEEK");break;
case 0xcf:printf("LEN");break;
case 0xd0:printf("STR$");break;
case 0xd1:printf("VAL");break;
case 0xd2:printf("ASC");break;
case 0xd3:printf("STICKX");break;
case 0xd4:printf("STICKY");break;
case 0xd5:printf("ACTION");break;
case 0xd6:printf("KEY");break;
case 0xd7:printf("CHR$");break;
case 0xd8:printf("LEFT$");break;
case 0xd9:printf("RIGHT$");break;
case 0xda:printf("MID$");break;
case 0x00:printf("\n");break;
default:printf("unknown token %02x",token);

}
}

int main(int argc,char *argv[],char *envp[])
{
FILE *fp;

int linenumber,offset,token,c;

fp=fopen(argv[1],"r");
if (fp)
{

c=fgetc(fp);
if (c!=0x20)
{
printf("%s is not a regular basic file\n",argv[1]);
fclose(fp);
return 2;
}

// find start of program
fseek(fp,16+9,SEEK_SET);
do
{
offset=fgetc(fp)+(fgetc(fp)<<8);
linenumber=fgetc(fp)+(fgetc(fp)<<8);
if (offset)
{
printf("%05d ",linenumber);
do
{
if (feof(fp)) break;
c=fgetc(fp);
if ((c>31) && (c<128)) putchar(c);
else  decode(c);
} while (c);
}
} while (!feof(fp));
fclose(fp);
}
else
{
printf("Could not open %s\n",argv[1]);
return 1;
}
}


Title: Re: C7420 basic stuff
Post by: Rafael on April 21, 2011, 09:57:35 PM
Can you post a video of it in action?


Title: Re: C7420 basic stuff
Post by: gertk on April 26, 2011, 12:29:17 AM
Can you post a video of it in action?

Here is a small video, the invaders are not yet animated here, I am optimizing the "put invaders" routine by replacing the blank self defined characters by normal 'space'(ASCII 32) characters so I can detect the left and right limits by scanning for non space characters in the video memory. The invaders leave a 'blank trail' when moving left and right.
Sorry for the blurry picture: my G1 phone could not focus in video mode with the black background.

http://www.youtube.com/watch?v=MsPe2Wa246Y (http://www.youtube.com/watch?v=MsPe2Wa246Y)


Title: Re: C7420 basic stuff
Post by: gertk on April 26, 2011, 12:55:00 AM
BTW, I finally found the memory corruption bug in the Z80 emulator:

The emulated command BIT n,(HL) had a 'store to memory' added where it should not store anything at all... (it is just a bit test)
This led to address $1faa,$1fab,$1fae (a value in HL) being written over by garbage and since I masked out/limited the memory by doing a logic AND with $3FFF this was right in the middle of the basic program space. I found out by printing to the debug terminal whenever any ram address outside the range $8000-$BFFF was being read or written to.

For Ren?: you added some text at the bottom of the source about the RAM test at location 3010, assuming it would test first at $FFFF then at $BFFF but my 'warning system' did not detect any read/write to $FFFF, only to $BFFF.

At least the helicopter program loads and runs 'full size' now.


Title: Re: C7420 basic stuff
Post by: Rene_G7400 on April 26, 2011, 01:09:40 AM
For Ren?: you added some text at the bottom of the source about the RAM test at location 3010, assuming it would test first at $FFFF then at $BFFF but my 'warning system' did not detect any read/write to $FFFF, only to $BFFF.

In the service manual of the C7420 a 32k RAM option is mentioned. I don't know any C7420 that has that option installed, but I've added two RAM chips to one of my C7420's. But it doesn't detect the extra RAM, so my idea was to modify the ROM, so the program would check the amount of installed RAM at start-up. (There is a BASIC instruction which makes it possible to use the extra RAM (CLEAR 50,-2), but it would be easier if it would be detected automatically.)



Title: Re: C7420 basic stuff
Post by: gertk on April 26, 2011, 07:35:16 AM
In the service manual of the C7420 a 32k RAM option is mentioned. I don't know any C7420 that has that option installed, but I've added two RAM chips to one of my C7420's. But it doesn't detect the extra RAM, so my idea was to modify the ROM, so the program would check the amount of installed RAM at start-up. (There is a BASIC instruction which makes it possible to use the extra RAM (CLEAR 50,-2), but it would be easier if it would be detected automatically.)

Ah, so it was more a reminder for the 'todo' list  :)
BTW: the BIT n,(HL) bug I found is also present in the original source of the ZX81 emulator of which I used the Z80 emulator part.

Furthermore it would be nice to get the Z80/C7420 emulator in O2EM so more people can experiment with the Basic. 


Title: Re: C7420 basic stuff
Post by: Rafael on April 26, 2011, 10:35:29 PM
Quote from: gertk link=topic=1632.msg14218#msg14218

Here is a small video [url=http://www.youtube.com/watch?v=MsPe2Wa246Y
http://www.youtube.com/watch?v=MsPe2Wa246Y[/url]


Thanks, Gertek. I tried your code on sunday and it?s really nice. I don?t know why but the bottom row of invaders was not appearing correctly. Hope to see it ready soon :)


Title: Re: C7420 basic stuff
Post by: Rene_G7400 on April 26, 2011, 11:12:05 PM
This is some doodling I did (trying to port space invaders to C7420 basic)
The program is far from finished, lots of the subroutines need to be filled in and it is way too slow now...

I wonder if you can get it fast enough, because I've never seen a Basic program with fast moving graphics on the C7420. (I've tried every program of the french C7420 book, and most of them are very slow.)


Title: Re: C7420 basic stuff
Post by: gertk on April 27, 2011, 11:17:29 AM
Quote from: gertk link=topic=1632.msg14218#msg14218

Here is a small video [url=http://www.youtube.com/watch?v=MsPe2Wa246Y
http://www.youtube.com/watch?v=MsPe2Wa246Y[/url]


Thanks, Gertek. I tried your code on sunday and it?s really nice. I don?t know why but the bottom row of invaders was not appearing correctly. Hope to see it ready soon :)

Ooh, did you really type it al the way in ?  ;:) Or did you use a program to create a wave file ?

I know I have the big advantage of saving to sdcard and I can edit the ASCII file on the host PC and let the host PC type in the program character by character (which is not fast but is nice to see) After that I can save it to the sdcard.

The 'put invader' routine can be optimized quite a bit further but at the moment I made the program above I still had the memory corruption bug in the emulator and wanted to get that nasty bug out first.

I already tried some ideas like putting the 3 characters per invader in a string-array, that way you can put the whole invader at once and I want to eliminate all the selfdefined characters which contain only zeros and replace them by $20 (32).

The invaders were also in the wrong order.
In the original space invaders coordinates 0,0 were in the lower left corner and the screen was in portrait mode so all bitmaps were vertical which was great for smooth movement horizontally. Furthermore it had a hardware 'barrelshifter' for moving things vertical pixel by pixel. I will post the updated source here in a few days.


Title: Re: C7420 basic stuff
Post by: gertk on April 27, 2011, 11:32:06 AM
This is some doodling I did (trying to port space invaders to C7420 basic)
The program is far from finished, lots of the subroutines need to be filled in and it is way too slow now...

I wonder if you can get it fast enough, because I've never seen a Basic program with fast moving graphics on the C7420. (I've tried every program of the french C7420 book, and most of them are very slow.)

Well, the nice thing is you can always revert to some Z80 assembler subroutines by using the USR(adr) function. The communication speed between the Z80 and the 8048 is not super fast but with space invaders you need to update only 1 invader per frame and so at most two screen lines need to be copied per frame which is perfectly doable. The game speeds automatically up when you eliminate each invader. Pre-calculation and smart array use can also help in speeding things up. The base and bullets could be made VDC sprites. The collission detection between VDC sprites and Plus graphics is sent along with the keyboard and joystick data to the Z80 but I don't know if there is an easy way to read it in the Basic part.
 


Title: Re: C7420 basic stuff
Post by: Rafael on April 28, 2011, 10:39:50 PM
Ooh, did you really type it al the way in ?  ;:) Or did you use a program to create a wave file ?
  Yes, I typed it
I just wanted to see some Invaders on my room. But I hope it be the last time until I buy a cassete recorder ;:) ;:)


Title: Re: C7420 basic stuff
Post by: gertk on April 28, 2011, 11:24:00 PM
  Yes, I typed it
I just wanted to see some Invaders on my room. But I hope it be the last time until I buy a cassete recorder ;:) ;:)
I think it is easier to connect the C7420 to your PC and let that do the recording and playback. That way you can even get the source back from the audio file you record on the PC with the migration tool at http://www.ifs.tuwien.ac.at/dp/hc_audio_migration/
Ren? can tell if it is also possible to create wave files from a given basic source with that tool. That would save a lot of typing.

I updated the source in the first message, it is a bit optimized both in the number of self-defined characters used and in the way they are put on screen. The screen now looks like the original space invaders with all invaders present and the horizontal movement, limit checks,  swooping down and animation works too. It is still dead-slow though, and there is nothing to shoot with... Every gosub and return costs enormous amounts of CPU time it seems. This C7420 Basic is truly a Microsoft product  :D


Title: Re: C7420 basic stuff
Post by: Rene_G7400 on April 29, 2011, 04:10:38 PM
It is still dead-slow though, and there is nothing to shoot with... Every gosub and return costs enormous amounts of CPU time it seems.

So it's time to switch to Z80 assembler programming.....?


Title: Re: C7420 basic stuff
Post by: gertk on April 29, 2011, 05:45:37 PM
It is still dead-slow though, and there is nothing to shoot with... Every gosub and return costs enormous amounts of CPU time it seems.

So it's time to switch to Z80 assembler programming.....?

;:) Yeah in Z80 or in 8048 assembler without the Basic module (ha)... All in all it proves you can do smooth hi-res on the G7400 chipset by carefully presetting your self defined characters. I also tried redefining the invader characters on the fly and that is also a neat way to do animation. In most space invader clones you see all invaders change shape at once and also move as one block which is much easier but not the way it is done in the original.

 


Title: Re: C7420 basic stuff
Post by: manopac on May 03, 2011, 10:53:50 AM
I think it is easier to connect the C7420 to your PC and let that do the recording and playback. That way you can even get the source back from the audio file you record on the PC with the migration tool at http://www.ifs.tuwien.ac.at/dp/hc_audio_migration/
Ren? can tell if it is also possible to create wave files from a given basic source with that tool. That would save a lot of typing.

I somehow missed this message - yes, of course its possible ... you can just create a new file (File -> New -> Basic Program, and give it a name, e.g. spacei), copy the source from the first post in, and export it as a wav-file (or do a direct Audio-playback, if you have your C7420 connected) ...

btw: gertk: it can also export it as a raw-binary for use on your SD-card ...


Title: Re: C7420 basic stuff
Post by: gertk on May 03, 2011, 10:29:16 PM
btw: gertk: it can also export it as a raw-binary for use on your SD-card ...

Yes, I have been playing a bit with this already.
I have found out that syntax checking/keyword recognition  is working only if you put spaces around the keywords (?)
Other thing is: if I save it in raw binary format the 0xFF padding is still in the file (in front of the header and in front of the program itself) which in this day and age with GBytes to spare is not really a problem anymore but my emulated CSAVE only saves the 24 byte header, a zero byte and then programdata. With a few lines of shell scripting this could be converted easily though.

My second mbed has arrived with another prototyping board so I hope to find the time to make this into the 'universal rom and other addons emulation cartridge' prototype. Someone also made a lowcost version of the mbed module (without Ethernet and without the direct option to compile and upload to the module from the 'cloud' compiler)
That module might be usable for an affordable 'production' model, that is: if my theory works...


 


Title: Re: C7420 basic stuff
Post by: gertk on May 17, 2011, 09:21:04 PM
Some more fiddling to make programming a bit easier:

This converter program converts an ASCII (text) Basic program into the binary form the C7420 uses. It produces no header yet, maybe Ren? can help me out in filling in the header bytes. This program differs from Ren?'s converter in so far that it also recognizes basic commands which are not seperated by spaces:

for example:

10PRINTSPC(10);"Hello World!":PRINTSTICK(0)

This program is meant to be a backend to a kind of pre-processor I have made (years ago for a 8052AH Basic processor) in which you can write a basic program using labels instead of linenumbers. The pre-processor converts the source then into a standard line numbered basic program but still in ASCII form. After pre-processing the converter generates the binary form.

Code:
// Tokenizer program for converting BASIC 80 source code to
// tokenized (binary) form data
// by Gert van der Knokke (c)2011

#include <stdio.h>
#include <string.h>
#define DEBUG   false


// my pseudo ram space
unsigned char ramspace[16384];
#define RAMEND 2048

#define MAXTOKENS 91
static char token[MAXTOKENS][10]={"END","FOR","NEXT","DATA","INPUT","DIM","READ","LET",
"GOTO","RUN","IF","RESTORE","GOSUB","RETURN","REM",
"STOP","ON","LPRINT","DEF","POKE","PRINT","CONT",
"LIST","LLIST","CLEAR","CLOAD","CSAVE","TX","GR",
"SCREEN","LINE","DISPLAY","STORE","INIT","CURSORX",
"CURSORY","SCROLL","PAGE","BRIGHT","SOUND","DELIM",
"SETET","SETEG","ET","EG","NEW","TAB(","TO","FN",
"SPC(","THEN","NOT","STEP","+","-","*","/","^","AND",
"OR",">","=","<","SGN","INT","ABS","USR","FRE","LPOS",
"POS","SQR","RND","LOG","EXP","COS","SIN","TAN","ATN",
"PEEK","LEN","STR$","VAL","ASC","STICKX","STICKY",
"ACTION","KEY","CHR$","LEFT$","RIGHT$","MID$"};

#define BASICOFFSET 0x88C1
#define TAPEOFFSET 25

// This functions compares all tokens with given string
// and returns a token number or NULL if no token is found
// Since it compares the exact length of the token even tokens
// not seperated by spaces are recognized (from left to right)
int checktoken(char *string)
{
int t=0,s=0;

// scan for all tokens
while (s<MAXTOKENS && !t)
{
#if DEBUG
printf("comparing %s with token %s\n",string,token[s]);
#endif
// no use comparing strings of smaller size
if (strlen(string)>=strlen(token[s]))
{
// if a token compares to tokenlength characters of the string
// a token is positively found and the loop is finished
if (!strncmp(token[s],string,strlen(token[s]))) t=s+0x80;
}
s++;
}
// return token value or NULL if no token found
return t;
}

// hexdump ramspace to standard output in 'hexdump -C' style
void hexdump(int limit)
{
char ascbuf[16];
int n,m;
int c;

if (!limit) limit=RAMEND;

for (n=0; n<limit; n+=16)
{
printf("%08x  ",n+TAPEOFFSET);
for (m=0; m<16; m++)
{
c=ramspace[n+m] & 0xff;
printf("%02x ",c & 0xff);
// hexdump -C style
if (m==7) printf(" ");
if (c>31 && c<128) ascbuf[m]=c;else ascbuf[m]='.';
}
ascbuf[m]=0;
printf(" |%s|\n",ascbuf);
}
}

// the main event
int main(int argc,char *argv[],char *envp[])
{
  FILE *fp;
  char inbuf[256];
char temp[256];
int c;
int quoteflag,ignoreflag;
int n,m,r,t,pos,startpos;
char *valid;

// pointer in my ram space
pos=0;
 
// try to open the input file...
fp=fopen(argv[1],"r");

// if it worked, then start the process
if (fp)
{
// loop until end of file
do
{
// first reset offsetpointers and flags
n=0;
quoteflag=0;
ignoreflag=0;

// make inbuf a zero length string
inbuf[n]=0;

// read one line of input
valid=fgets(inbuf,255,fp);

// if a line is succesfully read
if (valid)
{
// get rid of the 0x0a at the end of the line
if (inbuf[strlen(inbuf)-1]==0x0a) inbuf[strlen(inbuf)-1]=0;

#if DEBUG
// show original line
printf("%s\n",inbuf);
#endif
// now scan for linenumber
while (isdigit(inbuf[n])) temp[n]=inbuf[n++];

// close temporary string
temp[n]=0;


// read value from string in 'r'
sscanf(temp,"%d",&r);
#if DEBUG
printf("read linenumber %d from %s\n",r,temp);
#endif
// save current position
startpos=pos;

// reserve 2 bytes for offset
ramspace[pos++]=0x00;
ramspace[pos++]=0x00;

// store binary linenumber in rambuffer
ramspace[pos++]=(r & 0xff);
ramspace[pos++]=(r >> 8);


// skip spaces after linenumber
while (inbuf[n]==0x20) n++;

// now proces this line character by character until end of string (NULL)
while (inbuf[n])
{
t=0; // clear token number

//  toggle quoteflag if quotes are found (string start or end)
if (inbuf[n]==0x22) quoteflag=!quoteflag;

// check for tokens if quoteflag and ignoreflag are not set
if (!quoteflag && !ignoreflag)
{
// check for tokens at current offset (n)
t=checktoken(inbuf+n);
if (t) // we've found a token
{
// now skip tokenlength characters in inputbuffer
n+=strlen(token[t & 0x7f]);
// write token code into output buffer
ramspace[pos++]=t;
// set ignoreflag to ignore all (!) tokens
// until end of line if token was a REM (0x8e)
if (t==0x8e) ignoreflag=1;
} // end if (t)
} // end if (!quoteflag && !ignoreflag)

// if no token found or in ignore or string mode...
if (!t)
{
// copy literally to ramspace and advance pointer(s)
// convert some special chars to Videopac's equivalent
c=inbuf[n];
switch (c)
{
case '$':c=0x04; break;
case '#':c=0x06; break;
case '^':c=0x7f; break;
case 0xa3:c=0x03; break;
case 0xa8:c=0x7e; break;
}
ramspace[pos++]=c;
n++;
} // end if (!t)
} // end while (inbuf[n])

// write a NULL byte at the end of this tokenized line
ramspace[pos++]=0x00;

// fill in the current offset in the reserved offset bytes
ramspace[startpos]=(pos + BASICOFFSET) & 0xff;
ramspace[startpos+1]=(pos + BASICOFFSET) >> 8;
} // end if valid
}
while (valid);

// close the file
fclose(fp);

// show the result in hex
hexdump(pos);
}
else
{
// error...
printf("could not open %s!\n",argv[1]);
return 1;
}
 
}




Title: Re: C7420 basic stuff
Post by: gertk on May 17, 2011, 09:35:23 PM
An example of the ASCII text which the pre-processor uses for input (this file is edited on a PC):

Code:
\ -------------------------------------------------------
\ - Pipepanic for Basic 80 Videopac Basic / VG 5000
\ -------------------------------------------------------
~start
                INIT 7
                DEF FNTK(N)=TI
\ ------------------------------------------------
\               Startup
\ ------------------------------------------------
                BH=10:BW=10
                DIM HB(5,BW*BH):DIM HT(5)
                DIM BA(BH,BW):DIM PA(105)
                DIM DP(BH*BW+1,3):DIM PR(3)
                DIM PO(75,4)
                FOR C=0 TO 4:FOR C2=0 TO (BW*BH)-1
                        HB(C,C2)=255
                NEXT C2:NEXT C
\ ------------------------------------------------
\               * init bitmaps *
\ ------------------------------------------------
                GOSUB ~initbitmaps
\ ------------------------------------------------
\               * initialise new game *
\ ------------------------------------------------
                GOSUB ~initnewgame
~mainloop
\ ------------------------------------------------
\               main loop
\ ------------------------------------------------
                IF QT THEN END
                TI=TI+1
\ ------------------------------------------------
\               * GAMESHOWHELP *
\ ------------------------------------------------
~testhelp
                IF GM<>5 THEN ~testgameon
                GOSUB ~drawgame

\ ------------------------------------------------
\               * GAMEON *
\ ------------------------------------------------
~testgameon
                IF GM<>4 THEN ~testcleardeadpipes
                IF ABS(FNTK(0)-GI)<25 THEN ~testcleardeadpipes
                RD=RD OR 16
                GI=FNTK(0):GT=GT-1
                IF GT<=0 THEN GT=0:GOSUB ~createdeadpipesarray
                GOSUB ~drawgame

\ ------------------------------------------------
\               * GAMECLEARDEADPIPES *
\ ------------------------------------------------
~testcleardeadpipes
                IF GM<>3 THEN ~testgamefillpipes
                IF ABS(FNTK(0)-CD)<5 THEN ~skipcdset
                CD=FNTK(0):GOSUB ~cleardeadpipes
~skipcdset
                GOSUB ~drawgame

The pre-processor on the PC then generates this:

Code:
10 INIT 7
20 DEF FNTK(N)=TI
30 BH=10:BW=10
40 DIM HB(5,BW*BH):DIM HT(5)
50 DIM BA(BH,BW):DIM PA(105)
60 DIM DP(BH*BW+1,3):DIM PR(3)
70 DIM PO(75,4)
80 FOR C=0 TO 4:FOR C2=0 TO (BW*BH)-1
90 HB(C,C2)=255
100 NEXT C2:NEXT C
110 GOSUB 1230
120 GOSUB 1240
130 IF QT THEN END
140 TI=TI+1
150 IF GM<>5 THEN 170
160 GOSUB 1730
170 IF GM<>4 THEN 230
180 IF ABS(FNTK(0)-GI)<25 THEN 230
190 RD=RD OR 16
200 GI=FNTK(0):GT=GT-1
210 IF GT<=0 THEN GT=0:GOSUB 400
220 GOSUB 1730
230 IF GM<>3 THEN 270
240 IF ABS(FNTK(0)-CD)<5 THEN 260
250 CD=FNTK(0):GOSUB 1040
260 GOSUB 1730

All linenumbers and GOSUBS/GOTO's are calculated by the pre-processor. But you still need to type it in.. So now it needs to be converted to binary form (or WAV/MP3 for use on the original C7420 module) and that is where you need Ren?'s converter (or mine...)