News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_cpcitor

Load using firmware loader with messages, without "Press Play then any key".

Started by cpcitor, 20:57, 09 November 17

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

cpcitor

Hello.

I put a simple basic loader before my binary game.

On a disc it's pretty simple and works. load"mybinary", well, loads the binary.

On a tape, load"mybinary" asks "again" the user to "Press Play then any key", which is pointless because the loader just loaded and the user hasn't got a chance to stop the cassette yet.

Also, when sending to a CPC via an audio cable, the sending side does not wait for the user, so that wait can have the CPC miss blocks and destroy the process.

I *do* want the messages "loading xxx block 1", because they are useful to rewind in case of error.
And errors do happen sometimes when I send at high speed, so I want to see them and I want the end user to see them, although convention at the old time was to load"!mybinary" which would hide everything.

Is there a simple way to load using the firmware loader but (1) without asking user to "Press Play then any key"? (2) keeping the other firmware messages?

Some POKE maybe?
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

arnoldemu


load"!mybinary"


The ! tells firmware to turn off messages and to not ask to press a key.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

cpcitor

Quote from: arnoldemu on 21:53, 09 November 17
The ! tells firmware to turn off messages and to not ask to press a key.

Yes, as I stated above, my question is how to prevent a pause but keep the messages..

I'm afraid the firmware does not allow to skip the "press play" message yet show the other messages. If it's possible with very small code (like a poke or two), that would be great!

(I have an alternative idea: perhaps a trick (POKE) to insert a fake key event in the keyboard event queue, so that then the message "Press Play then any key" appears, the firmware goes on immediately. See http://www.cpcwiki.eu/forum/programming/insert-key-in-keyboard-event-queue/new/#new for that idea)
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

cpcitor

Reading Soft968 section 8:

Quote
The messages that prompt or inform the user may be turned
on or off as desired (see CAS NOISY). Messages that inform the user of errors cannot be
turned off by this mechanism.

So it seems that "read error" and "rewind tape" are still shown. In other words, the load"! is indeed enough?

I must have been fooled by some loaders from games where they aren't shown ever.

I'll test that.
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

ssg

Quote from: cpcitor on 22:10, 09 November 17
Yes, as I stated above, my question is how to prevent a pause but keep the messages..

I'm afraid the firmware does not allow to skip the "press play" message yet show the other messages. If it's possible with very small code (like a poke or two), that would be great!

(I have an alternative idea: perhaps a trick (POKE) to insert a fake key event in the keyboard event queue, so that then the message "Press Play then any key" appears, the firmware goes on immediately. See http://www.cpcwiki.eu/forum/programming/insert-key-in-keyboard-event-queue/new/#new for that idea)


Unfortunately that doesn't work. Because the loader code is in ROM, you can't really patch it as far as I know. You'll have to go about writing your own loader in assembly. It's not actually that hard because firmware has "block load" functions. You can load header blocks, data blocks and display the information accordingly and implement rewinding logic etc.

cpcitor

Summary: thanks SSG! Very nice hint!


For the reminder: CAS NOISY off (or load"!") prevent "press play then any key", also prevent "loading xxx block n", allow "read error a/b" and "rewind tape".
Original wish is only disallow "press play then any key", yet keep "loading xxx block n".



Quote from: ssg on 09:59, 10 November 17
You'll have to go about writing your own loader in assembly. It's not actually that hard because firmware has "block load" functions. You can load header blocks, data blocks and display the information accordingly and implement rewinding logic etc.

Yes!

My first motivation here is to make a very short/small initial loader that very quickly display a minimal title/banner, while the rest of the loading process is "mostly regular firmware load".

Your feedback is interesting because it provides a solution keeping short code and thus quick feedback plus the added benefit that display can be customized fairly easily.

I guess that's what some games used. I remember a game showing a loading progress countdown at the top of the screen. The number started relatively high (like 72 or 99) but changes often (perhaps every 2-3 seconds). Probably *that* one used more custom loading primitives anyway.  It was not highway encounter (that one shows custom blocks but no countdown).

My idea: a progress bar showing color regions for unloaded/loading/loaded blocks, plus an arrow showing tape position (useful when rewind is needed).

Quote from: ssg on 09:59, 10 November 17
Unfortunately that doesn't work. Because the loader code is in ROM, you can't really patch it as far as I know.

Any time someone in a CPC context says "it's in ROM", a reflex kicks in, that says "perhaps the fine engineers at Locomotive Software provided a jump block for that".

Paragraph 8.13 of Soft968 reads:

QuoteTo allow the user to produce a new filing system the record read and write routines, CAS READ and CAS WRITE, are in the firmware jumpblock.

This suggest an approach. In loader:
* divert the CAS READ jumblock so that it does:
* set CAS NOISY to on
* restore CAS READ jumpblock
* jump to upstream CAS READ
* once the jump block is diverted, call LOAD"!"

This way, the messages and pause will be initially inhibited (so no "press play then any key"), yet they are activated again even before first block is actually read.

So, it would perfectly satisfy the requirement:
* no "Press play then any key", no pause
* yes to all "Loading xxx block n" messages


SSG's suggestion is more powerful and flexible, yet this hack might find some use due to simplicity.
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

Docent

Quote from: cpcitor on 15:34, 10 November 17
Summary: thanks SSG! Very nice hint!


For the reminder: CAS NOISY off (or load"!") prevent "press play then any key", also prevent "loading xxx block n", allow "read error a/b" and "rewind tape".
Original wish is only disallow "press play then any key", yet keep "loading xxx block n".



Yes!

My first motivation here is to make a very short/small initial loader that very quickly display a minimal title/banner, while the rest of the loading process is "mostly regular firmware load".

Your feedback is interesting because it provides a solution keeping short code and thus quick feedback plus the added benefit that display can be customized fairly easily.

I guess that's what some games used. I remember a game showing a loading progress countdown at the top of the screen. The number started relatively high (like 72 or 99) but changes often (perhaps every 2-3 seconds). Probably *that* one used more custom loading primitives anyway.  It was not highway encounter (that one shows custom blocks but no countdown).

My idea: a progress bar showing color regions for unloaded/loading/loaded blocks, plus an arrow showing tape position (useful when rewind is needed).

Any time someone in a CPC context says "it's in ROM", a reflex kicks in, that says "perhaps the fine engineers at Locomotive Software provided a jump block for that".

Paragraph 8.13 of Soft968 reads:

This suggest an approach. In loader:
* divert the CAS READ jumblock so that it does:
* set CAS NOISY to on
* restore CAS READ jumpblock
* jump to upstream CAS READ
* once the jump block is diverted, call LOAD"!"

This way, the messages and pause will be initially inhibited (so no "press play then any key"), yet they are activated again even before first block is actually read.

So, it would perfectly satisfy the requirement:
* no "Press play then any key", no pause
* yes to all "Loading xxx block n" messages


SSG's suggestion is more powerful and flexible, yet this hack might find some use due to simplicity.

Your suggestion will probably not work because basic do not use CAS READ - it loads data via CAS IN DIRECT. Additionally, CAS READ will not load a whole program ( CAS IN DIRECT does this) but it can be used, as SSG suggested, to load data from cassette but you will need to process each block separately and provide your own messages. The code might look like this:

loadfile:
; disable messages
di
ld a, 1
ld (blocktoload), a
call &bc6b ;cas_noisy
ld hl, searchingstr
ld b, 25
call printstr
loaddata:
;load header
ld a, #2c
ld hl, headerbuf
ld de, 64
call &BCA1 ; cas read
jr nc, error
ld a, (headerbuf+16)
ld hl, blocktoload
cp (hl)
jr z, loadblock
; rewind
ld hl, foundstr
ld b, 7
call printstr
call printblock
ld hl, rewindstr
ld b, 13
call printstr
jr loaddata
loadblock:
; display message
ld hl, loadingstr
ld b, 9
call printstr
call printblock
ld hl, blocktoload
inc (hl)
; load data block
ld de, (headerbuf+19)
ld hl, (headerbuf+21)
ld a, &16
call &BCA1
jr nc, error
ld a, (headerbuf+17)
or a
jr z, loaddata
; execute
ei
ld hl, (headerbuf+26)
jp (hl)
error:
or a
jr nz, loaderror
ei
ld hl,breakstr
ld b, 10
jp printstr
loaderror:
push af
ld hl,errorstr
ld b, 13
call printstr
pop af
add a, "`"
call &bb5a
jr loaddata
printblock:
ld hl, headerbuf
ld b, 15
call printstr
ld hl, blockstr
ld b, 7
call printstr
ld a, (headerbuf+16)
jp printhex
printstr:
ld a, (hl)
inc hl
call &bb5a
djnz printstr
ret
printhex:
push af
rrca           
rrca
rrca
rrca
call printdigit
pop af
printdigit:
and &f
add a,"0"
cp "9"+1       
jr c,number
add a,"A"-"9"-1
number:
jp &bb5a
blocktoload:
db 1
searchingstr:
db 13, 2, "searching for files...", 10
loadingstr:
db 13, "loading "
foundstr:
db 13, "found "
blockstr:
db " block "
rewindstr:
db 10, 13, "rewind tape"
errorstr:
db 10, 13, "read error "
breakstr:
db " Break.", 10, 13, 3
headerbuf:
defs 64,0


This will load any file from cassette into the address from its header and run it just like run"!" from basic but with all messages displayed. You can customize it as you need, for example load blocks using different numbering scheme (in descending order for example, or load with a different sync (first save via CAS WRITE with such sync) for a simple copy protection :))



cpcitor

Quote from: Docent on 01:00, 11 November 17
Your suggestion will probably not work because basic do not use CAS READ - it loads data via CAS IN DIRECT.

Really? Oops, the quote from the firmare wasn't there. Here it is:

QuoteTo allow the user to produce a new filing system the record read and write routines, CAS
READ and CAS WRITE, are in the firmware jumpblock. There is a third routine at this
level, CAS CHECK, whose facilities are not used by the higher levels of the Casssette
Manager. It allows the data that has been written to tape to be compared with the data in
store. This could be used to perform a read after write check if so desired.

This suggests that firmware uses CAS IN DIRECT which in turn uses CAS READ, which once diverted can have the desired effect. Anyway.

Quote from: Docent on 01:00, 11 November 17
The code might look like this:

loadfile:
; disable messages
(...)
db " Break.", 10, 13, 3
headerbuf:
defs 64,0


This will load any file from cassette into the address from its header and run it just like run"!" from basic but with all messages displayed. You can customize it as you need, for example load blocks using different numbering scheme (in descending order for example [...]

Excellent! Your code compiled to 330 bytes with pasmo.

From the code I take that when CAS READ returns with carry and A=0 it means "break", which in my memory happened with keeping "Esc" key pressed during loading. This in turn reminds me that firmware re-enables interrupts between blocks, to provide the user a chance to interrupt load operation.

It looks like the code will exit on error instead of having any chance to actually re-read a block.

Where does this source come from? One of your past prod? Prod from someone else?

Thanks!
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

Docent

Quote from: cpcitor on 06:11, 11 November 17
Really? Oops, the quote from the firmare wasn't there. Here it is:

This suggests that firmware uses CAS IN DIRECT which in turn uses CAS READ, which once diverted can have the desired effect. Anyway.

As I said, basic rom doesn't call CAS READ, it just calls CAS IN DIRECT to load or run programs and os doesn't use jump block - it just jumps directly to the address in rom, so it will not work for basic. It may work with programs calling jumpblock functions to load  a file.

Quote from: cpcitor on 06:11, 11 November 17
Excellent! Your code compiled to 330 bytes with pasmo.

From the code I take that when CAS READ returns with carry and A=0 it means "break", which in my memory happened with keeping "Esc" key pressed during loading. This in turn reminds me that firmware re-enables interrupts between blocks, to provide the user a chance to interrupt load operation.

Os during loading checks only escape key if it was pressed without any interrupts, so it doesn't matter if they are enabled or not.

Quote from: cpcitor on 06:11, 11 November 17
It looks like the code will exit on error instead of having any chance to actually re-read a block.

No, the code exits only when user presses esc. In case of any read error it will ask you to rewind to beginning of the block it was loading. Further blocks will be shown as "found" an not "loading", just like in basic.

Quote from: cpcitor on 06:11, 11 November 17

Where does this source come from? One of your past prod? Prod from someone else?

Thanks!

I wrote it from scratch yesterday (except printhex which I had earlier)

cpcitor

Quote from: Docent on 00:50, 12 November 17
os doesn't use jump block - it just jumps directly to the address in rom, so it will not work for basic. It may work with programs calling jumpblock functions to load  a file.

You seem to know a lot about firmware and OS.
Cannot test right now but I'm not certain about OS not using jump blocks.
I remember seeing programs that provided double width/height/both printing RSX in BASIC.
They worked by diverting the jumpblock that the OS uses to draw chars.

Also, I remember personally diverting the same the most somple fashion: to another address. For example I did two pokes in BASIC and the OS dumped all text output to the printer. Even the "Ready" prompt. But not the line being edited (you could still type on-screen as usual, only you's see no "Ready", no output from BASIC, all went to printer).

So, at least some part of the OS use jumpblocks. Also the way Sotf968 states it:

QuoteTo allow the user to produce a new filing system the record read and write routines, CAS READ and CAS WRITE, are in the firmware jumpblock.

If the OS does not use those jumpblocks, this sentence makes much less sense. But perhaps you're right anyway.

Quote from: Docent on 00:50, 12 November 17
No, the code exits only when user presses esc. In case of any read error it will ask you to rewind to beginning of the block it was loading. Further blocks will be shown as "found" an not "loading", just like in basic.

Okay, I must have missed something when cold-reading the source code.

Thanks for sharing!
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

Docent

Quote from: cpcitor on 09:34, 12 November 17
You seem to know a lot about firmware and OS.
Cannot test right now but I'm not certain about OS not using jump blocks.
I remember seeing programs that provided double width/height/both printing RSX in BASIC.
They worked by diverting the jumpblock that the OS uses to draw chars.

Also, I remember personally diverting the same the most somple fashion: to another address. For example I did two pokes in BASIC and the OS dumped all text output to the printer. Even the "Ready" prompt. But not the line being edited (you could still type on-screen as usual, only you's see no "Ready", no output from BASIC, all went to printer).

So, at least some part of the OS use jumpblocks. Also the way Sotf968 states it:

If the OS does not use those jumpblocks, this sentence makes much less sense. But perhaps you're right anyway.


Jumpblocks are generally not for os to use but for user programs to run no matter what version of os is installed. The only part used by os is so called indirections - routines between BDCD and BDF6 (BDF3 on cpc464). They are related mainly with text and graphics output, so printing enhancers you mentioned might use them but altering other os jumpblocks will not affect os operations, because it doesnt use them. You can verify it by yourself looking into os source code.
Pokes you did probably just changed some os variables altering os behaviour.

cpcitor

Quote from: Docent on 23:20, 12 November 17
Jumpblocks are generally not for os to use but for user programs to run no matter what version of os is installed. The only part used by os is so called indirections - routines between BDCD and BDF6 (BDF3 on cpc464). They are related mainly with text and graphics output, so printing enhancers you mentioned might use them but altering other os jumpblocks will not affect os operations, because it doesnt use them. You can verify it by yourself looking into os source code.
Pokes you did probably just changed some os variables altering os behaviour.

Fully true, about jumpblocks and indirections.

Pokes I did were precisely changing the actual indirections that are meant to alter firmware behavior. I probably redirected BDD3 (TXT WRITE CHAR) to BD2B (MC PRINT CHAR) with pokes from BASIC (two pokes on one line). I was totally unsure whether it would work when I tried that at the time but it did.

Back to CAS READ and CAS WRITE, looking at RAM content in a CPC running, CAS READ / CAS WRITE are indeed entry points (RST xx), not indirections (JP).

All this confirmed by official firmware documentation section 14 posted by Kevin Thacker yesterday: http://www.cpcwiki.eu/forum/programming/soft968soft158-pdfs/msg151621/#msg151621

What firmware doc meant.

So, the quote about "allow the user to produce a new filing system" by changing CAS READ and CAS WRITE (say, to implement a different loading mechanism or tape encoding as a drop-in replacement compatible with third-party software) would only work with specific case of software that called those entries, not with BASIC or no-firmware programs that fully implement block reading/writing themselves. Interestingly, it would affect the ASM sample you wrote, and perhaps even some of commercial games loaders of the era?

How DDI-1 ROM changed BASIC LOAD"" SAVE"" commands behaviour.

QuoteThe firmware indirections listed here are taken at key points in the firmware thus
allowing the user to provide substitute routines for many firmware actions, without
having to replace a complete firmware package.

I guess the DDI-1 ROM on a CPC464 changes the behavior (of SAVE"", LOAD"", CAT) by "replacing a complete firmware package", right?


In any case, thank you for sharing your solid knowledge of CPC ROM and firmware!

Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

Docent

Quote from: cpcitor on 10:41, 13 November 17
So, the quote about "allow the user to produce a new filing system" by changing CAS READ and CAS WRITE (say, to implement a different loading mechanism or tape encoding as a drop-in replacement compatible with third-party software) would only work with specific case of software that called those entries, not with BASIC or no-firmware programs that fully implement block reading/writing themselves. Interestingly, it would affect the ASM sample you wrote, and perhaps even some of commercial games loaders of the era?

Yes, every program that uses any of these firmware jumps is affected.
Unfortunately, most commercial game loaders did not use any firmware for loading data - they had their own routines to do it.

Quote from: cpcitor on 10:41, 13 November 17
How DDI-1 ROM changed BASIC LOAD"" SAVE"" commands behaviour.

I guess the DDI-1 ROM on a CPC464 changes the behavior (of SAVE"", LOAD"", CAT) by "replacing a complete firmware package", right?

DDI rom works similarly to amsdos rom on 6128 - it patches 13 of the cassette manager entries and redirects them to his own disk routines and, because basic calls these firmware routines, everything is transparently redirected to disk.

Powered by SMFPacks Menu Editor Mod