![]() |
Forum Index : Microcontroller and PC projects : CMM2: initialising large arrays without DATA or files
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Hi folks, I'm writing some library code that needs to to initialise large arrays but I don't want to do it from DATA statements (1) and I don't want to read it from files (2). 1) Using DATA statements in library code seems to be inherently unsafe because unless you impose restrictions on the client you can't prevent it from reading the DATA in a random library .inc file instead of its own DATA. 2) Reading data from files in library code isn't much better because it relies on the files being in a fixed location, or the client telling the library where its files are. Currently this is the best I've come up with, but I'm hoping for a better solution: Function crypt.md5$(s$) ' Per-round shift amounts Local r%(array.new%(64)) Local i% = Mm.Info(Option Base) array.insert_ints(r%(), i%, 8, 7, 12, 17, 22, 7, 12, 17, 22) : Inc i%, 8 array.insert_ints(r%(), i%, 8, 7, 12, 17, 22, 7, 12, 17, 22) : Inc i%, 8 array.insert_ints(r%(), i%, 8, 5, 9, 14, 20, 5, 9, 14, 20) : Inc i%, 8 array.insert_ints(r%(), i%, 8, 5, 9, 14, 20, 5, 9, 14, 20) : Inc i%, 8 array.insert_ints(r%(), i%, 8, 4, 11, 16, 23, 4, 11, 16, 23) : Inc i%, 8 array.insert_ints(r%(), i%, 8, 4, 11, 16, 23, 4, 11, 16, 23) : Inc i%, 8 array.insert_ints(r%(), i%, 8, 6, 10, 15, 21, 6, 10, 15, 21) : Inc i%, 8 array.insert_ints(r%(), i%, 8, 6, 10, 15, 21, 6, 10, 15, 21) ' Binary integer part of the sines of integers (Radians) as constants Local K%(array.new%(64)) i% = Mm.Info(Option Base) array.insert_ints(K%(), i%, 4, &hd76aa478, &he8c7b756, &h242070db, &hc1bdceee) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &hf57c0faf, &h4787c62a, &ha8304613, &hfd469501) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &h698098d8, &h8b44f7af, &hffff5bb1, &h895cd7be) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &h6b901122, &hfd987193, &ha679438e, &h49b40821) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &hf61e2562, &hc040b340, &h265e5a51, &he9b6c7aa) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &hd62f105d, &h02441453, &hd8a1e681, &he7d3fbc8) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &h21e1cde6, &hc33707d6, &hf4d50d87, &h455a14ed) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &ha9e3e905, &hfcefa3f8, &h676f02d9, &h8d2a4c8a) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &hfffa3942, &h8771f681, &h6d9d6122, &hfde5380c) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &ha4beea44, &h4bdecfa9, &hf6bb4b60, &hbebfbc70) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &h289b7ec6, &heaa127fa, &hd4ef3085, &h04881d05) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &hd9d4d039, &he6db99e5, &h1fa27cf8, &hc4ac5665) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &hf4292244, &h432aff97, &hab9423a7, &hfc93a039) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &h655b59c3, &h8f0ccc92, &hffeff47d, &h85845dd1) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &h6fa87e4f, &hfe2ce6e0, &ha3014314, &h4e0811a1) : Inc i%, 4 array.insert_ints(K%(), i%, 4, &hf7537e82, &hbd3af235, &h2ad7d2bb, &heb86d391) ' This function is not finished ;-) End Function Sub array.insert_ints(a%(), lb%, num%, i0%, i1%, i2%, i3%, i4%, i5%, i6%, i7%, i8%, i9%) If num% < 1 Or num% > 10 Then Error "num% out of bounds 1..10" a%(lb%) = i0% If num% > 1 Then a%(lb% + 1) = i1% Else Exit Sub If num% > 2 Then a%(lb% + 2) = i2% Else Exit Sub If num% > 3 Then a%(lb% + 3) = i3% Else Exit Sub If num% > 4 Then a%(lb% + 4) = i4% Else Exit Sub If num% > 5 Then a%(lb% + 5) = i5% Else Exit Sub If num% > 6 Then a%(lb% + 6) = i6% Else Exit Sub If num% > 7 Then a%(lb% + 7) = i7% Else Exit Sub If num% > 8 Then a%(lb% + 8) = i8% Else Exit Sub If num% > 9 Then a%(lb% + 9) = i9% Else Exit Sub End Sub ' Gets the upper-bound that should be used to dimension an array of the given ' capacity, irrespective of OPTION BASE. ' ' e.g. To create a string array that can hold 10 elements: ' Dim my_array$(array.new%(10)) Function array.new%(capacity%) array.new% = capacity% + Mm.Info(Option Base) - 1 End Function Best wishes, Tom Edited 2021-05-13 06:48 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Possibly the answer is to either brute force it, e.g. r%(i% + 0) = 7 : r%(i% + 1) = 12 : r%(i% + 2) = 17 : r%(i% + 3) = 22 ... Or use a CSUB ![]() Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Deleted Edited 2021-05-13 06:48 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
Could you poke the data into strings? Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
Put the data into CSUB format and then use peek(cfunaddr, peek(VARADDR and MEMORY COPY |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Sounds like fun, I will definitely try that out. What is the intended purpose of Peek(CFunAddr foo) ? or is this it, to allow access to arbitrary binary data encoded in the program. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
epsilon![]() Senior Member ![]() Joined: 30/07/2020 Location: BelgiumPosts: 255 |
I'm missing the point about the DATA statements. E.g. If I would put the code below in a library, what makes it inherently unsafe? DIM CRSR_INS_SPRITE%(COL_WIDTH%*ROW_HEIGHT%-1) 'Insert cursor sprite CRSR_INS_SPRITE_DATA: DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 DATA FG_COLOR%, FG_COLOR%, 0, 0, 0, 0, 0, 0 SUB initInsSprite LOCAL ii% RESTORE CRSR_INS_SPRITE_DATA FOR ii%=0 TO COL_WIDTH%*ROW_HEIGHT%-1 READ CRSR_INS_SPRITE%(ii%) NEXT ii% END SUB initInsSprite Epsilon CMM2 projects |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
There is nothing in the BASIC language that enforces that all DATA sections are preceded by labels and that all code that reads data calls RESTORE <label> first. As a result naive/legacy client code may in ignorance read your DATA instead of their own. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
epsilon![]() Senior Member ![]() Joined: 30/07/2020 Location: BelgiumPosts: 255 |
Got it. Thanks for clarifying! Epsilon CMM2 projects |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
I've not tried this... RESTORE with no argument selects the first DATA statement *in the program*. Does that still apply in this case though? Would a DATA statement in the library actually be selected? Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
In all honesty I didn't try it. But when I say library I'm talking about .inc file and from everything Peter has said in the last 12+ months the pre-processing step just flattens everything, so once it hits the flash there is no distinction between code that came from a .inc file and that in the .bas file ... though it must be maintaining the origin somewhere to show in error messages. Of course I may be completely mistaken in my assumption in which case Peter will no doubt put me straight ... though in this case I think not ![]() Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
For the Micromite it depends on what "order" the library is relative to the program space. If the library comes *after* the program space then there's no problem - just use RESTORE <datalabel> in the library then RESTORE to reset the pointer to the first DATA statement in the program. That would be in an ideal world. :) I've never used inc files, but I assume they would come *before* the program. However, they aren't likely to be used with legacy programs any way, are they? Just make sure that RESTORE always has an argument. Edited 2021-05-13 21:29 by Mixtel90 Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Yes, but: 1. Most developers familiar with #include from other languages are in the habit of putting those statements first. 2. You put the onus on the client code to call RESTORE to reset the pointer, naive/legacy code doesn't. 3. This problem: library.one() RESTORE READ some data ... library.two() READ some more data ... which will fail because it is trying to read beyond the library data! END ' some data DATA ... ' some more data DATA ... ' The following comes from a #Include SUB library.one() END SUB SUB library.two() RESTORE library.data READ library.data ... END SB library.data: DATA ... Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Yes, that's one possible fix, impose that restriction on any client code using your library. I was investigating whether there were other options. Edit: just in case it isn't clear the client code is not necessarily code written by me, hence wanting a robust solution that doesn't depend on someone reading any accompanying documentation. Edited 2021-05-13 21:36 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
I see that #INCLUDE inserts the file *at that point*, so using it at the end of the program would put your DATA statements at the end. You could then use RESTORE <name> anywhere to process them and RESTORE to point to the first program DATA. It's been a long time since RESTORE without a label or line number has been acceptable programming really. It's not something I commonly did on the TRS-80. :) Micromite: Library DATA statements will (apparently) be processed before program DATA statements, so it's not a perfect world. lol Edited 2021-05-13 21:52 by Mixtel90 Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Yes, the BEGINNING of the first program data. But see my 3rd point above. What it comes down to is that there is a single global resource, the data pointer, that naive client code might not expect "library" code to manipulate. Likewise there is a problem with "library" code and open file descriptors (another global resource). i.e. there is no file descriptor that a piece of library code can use that I can't guarantee the client code doesn't already have open. You could also argue the same for global variables, fortunately MMBasic allows "." in a variable name which I'm using to provide a poor persons namespacing facility, i.e. everything declared in the "crypt.inc" as the prefix "crypt." Note that I'm not complaining about any of this, BASIC is what it is, and MMBasic is a superior version of that. All I'm doing is fishing for other ideas and opinions whilst I decide how to handle it. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
I can't remember what I was doing that far back, I certainly wasn't trying to push BBC & Sinclair BASIC (and later AMOS) as hard then as I'm pushing MMBasic now. Best wishes, Tom Edited 2021-05-13 21:58 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
Personally, I think I'd opt for a single #INCLUDE at the beginning that pulls the data from a file with the proviso that the data file must be in the same directory as the program file. The #INCLUDE file has to be in the same directory anyway. Once the file is loaded into somewhere or other you can close the file descriptor and leave it free for the client program. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Not true, #INCLUDE statements can reference both absolute and relative paths. Thus there isn't any sane mechanism (you need to manually parse the current .bas file to find the #INCLUDE statements) for a .inc file to determine where it came from and thus locate a data file that it depends upon. So I believe that either data has to be packed into the code, or a library has to sit at a fixed known location, or the client code has to inform the library where it can find its own data. Best wishes, Tom Edited 2021-05-13 22:38 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
Ah... I see... Perhaps that's the condition of using your library that you need to specify, that the INC and DAT files are in the same directory as the program. The problem with embedding the data, unless you use DATA statements, would seem to be that any changes to it require a new version of the program - the two can never be separated. A file is definitely the most flexible. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |