|
Post by gsteemso on Oct 18, 2014 4:03:46 GMT
Hi all,
I recently read something (don’t recall when, where, nor who wrote it) about someone having, as a proof of concept, reimplemented VDC text mode via (IIRC) 8x8-pixel bitmap cells. Doing it that way let them give each cell its own background colour. That got me thinking, the only way to show a colour bitmap on the VDC is to do the 8x1-pixel-cells trick and assign each cell its own foreground-background colour pair. So, my question: How do people achieve that? As we all know, it’s not a feature Commodore remembered to build in, so how is it done?
|
|
|
Post by gsteemso on Oct 18, 2014 3:39:30 GMT
In thinking about this, I figure there are two aspects to consider: How much data needs to be sent over the serial bus, and how much processing needs to be done by the drive / by the computer. Assuming you want to do all processing in the 128, as not all drives support things like the BLOCK-EXECUTE command (I'm looking at you, µIEC and Flyer), there are two sets of CBM DOS commands I can think of that would achieve the desired result:
First, the sequence you already know about, assuming you have extracted the file name from the directory entry into the variable FN$:
100 OPEN {FILE #},{UNIT #},{CHANNEL #},"{DRIVE #}:"+FN$+",R" 105 GET#{FILE #},{string variable to hold file subtype} 110 GET#{FILE #},{string variable to hold file type} 115 CLOSE{FILE #}
…some of the details (e.g. ',R') could be omitted without much risk, but this is how the manual says to do it.
Assuming a file named TEST FILE on drive (or partition) 1 of unit 9, accessed through disk channel 4, this would (assuming I recall the details correctly) require the following to be sent over the serial bus:
C128: MTA9 CSO4 '1' ':' 'T' 'E' 'S' 'T' ' ' 'F' 'I' 'L' 'E' ',' 'R' Drive: [1-character subtype] C128: UNT MTA9 MSA4 Drive: [1-character type] C128: UNT MLA9 CSC4
That’s 8 bytes sent under /ATN (which is always done using slow serial, even if you have JiffyDOS), plus 15 bytes of data (which can be fastloaded). The minimal amount of data (i.e., if you have a 1-character filename, you default to drive 0, and you don’t bother with ',R') is 3 bytes and the maximum that might be required (you’re using a maxed-out 16-character file name on partition #107 on a CMD hard drive and you specify ',R') is 24.
The other way I could think of to do this is as follows, assuming you have the command channel (15) open on logical file number 50, buffer channel 5 open on logical file number 40, and have extracted the track and sector from the directory entry in the variables TK and SR:
105 PRINT#50,"U1";5;{DRIVE #};TK;SR 110 GET#40,{string variable to hold file subtype} 115 GET#40,{string variable to hold file type}
Note the major differences here: The code always takes close to the same amount of time to execute (ignoring the drive’s seek time, of course, and it’ll take a bit longer if you’re accessing 3-digit track and sector numbers on a CMD hard drive), and the logical file gets opened and closed exactly once instead of every time through the loop… not that that last point really matters much, but who knows. The question, of course, is "IS IT FASTER?"
To answer that, of course, I must once again hope I am recalling the details of the serial bus correctly and step through it. Once again assuming drive (or partition) 1 on unit 9, and the “average case” where the file’s first track and sector are two digits each (let’s say track 22/sector 11):
C128: MLA9 MSA15 'U' '1' ' ' '5' ' ' '2' '2' ' ' '1' '1' UNL MTA9 MSA5 Drive: [1-character subtype] C128: UNT MTA9 MSA5 Drive: [1-character type] C128: UNT
That’s 9 bytes sent under /ATN (e.g., slow), and 12 (at least 10 / at most 14) data bytes (which are fastloadable).
Hmm. I observe that both programs can be sped up by (3 bytes sent under /ATN, i.e., with slow serial) if you control the serial bus via machine language and read both data bytes in one go, but I don’t know how tangible the speed boost would be, if at all.
As is so often the case, your real-world results will depend on your data (i.e., how long your filenames are), but my gut feeling is that the second program will have a slight edge. Of course, “slight” can add up fast when you have a large number of files on the device. Only thing to do is try it both ways and see what you get.
EDIT: I did it again! I didn’t notice that this topic was in the “assembly language” subforum when I was composing my reply. I know all of this is easier in machine language but I do not recall off the top of my head what the routines to call are named.
|
|
|
Post by gsteemso on Oct 15, 2014 2:38:25 GMT
When I wrote that the # syntax wasn’t included in the BASIC reference, I hadn’t actually checked the MOVSPR entry, because I was operating under the mistaken assumption that the hash mark was acting as a BASIC operator or something of that sort. I had never seen a hash mark used in Commodore BASIC at all, anywhere, and had no idea how to pick apart the syntax of the original expression.
EDIT: With the obvious exceptions of GET#, INPUT#, PRINT#, and RECORD#, of course, but it’s part of the keyword with those. Not the same thing at all.
|
|
|
Post by gsteemso on Sept 30, 2014 3:19:47 GMT
Huh. Learn something new every day. Thanks for explaining that. That actually works out so neatly that I half-suspect the ANGLE # SPEED syntax was meant for this use, or some other closely-related use.
You could fix the -1*45° for joystick sitting still with a second use of the (j>0) comparison. Don’t even need to use ABS() — just multiply the expression by -45 instead of +45.
|
|
|
Post by gsteemso on Sept 29, 2014 5:06:13 GMT
This may seem a silly question, but what on Earth is achieved by having an unattached number sign in the middle of the expression like that? I’ve never seen that anywhere else, and there’s no mention of it in Hydrophilic’s BASIC reference pages. Actually, while I’m on the subject, how does that expression even work?
|
|
|
Post by gsteemso on Sept 27, 2014 23:22:03 GMT
The other way to do it is to do a Kernal SAVE and then use sector-access disk commands to set the first two bytes to whatever you like. There is no facility to load to a specific RAM configuration other than to do a chained LOAD with a little 1-block self-RUNning program that sets the correct bank configuration prior to calling the actual LOAD.
|
|
|
Post by gsteemso on Sept 27, 2014 23:16:42 GMT
No worries, something that basic has no nametag. :@)
|
|
|
Post by gsteemso on Sept 25, 2014 4:40:32 GMT
I guess another way to do that last bit would be:
LDA #$01 ; bitmask for CPU selection bit: currently 1 for 8502, 0 means Z80 EOR $D505 ; toggle it to Z80 state
This way at least has the advantage of not needing to work in negative logic, as is required with a logical AND.
|
|
|
Post by gsteemso on Sept 25, 2014 4:23:35 GMT
Sorry for the unhelpful reply, I misread your follow-up question. I suppose the most relevant question I have from this point is, “How are you getting to this code?” …or to put it more directly, “Where does that RTS at the end lead to?” Can’t really answer you without seeing that.
Also, I know it doesn’t really matter, but I noticed that the part where Hydrophilic turns this:
lda $d505 ; store mode pha ; to stack
into this:
lda $d505 ; store mode ;;; pha DO NOT SAVE TO STACK... Z80 will write $d505 to (re)activate 6502!
…could all (both instructions) just be deleted entirely, since nothing need be done with the value at that point.
After looking at the Compute!’s Mapping the Commodore 128 synopsis of register $D505, I further observe that setting it to a fixed value ($B0 in this case) is only appropriate for certain types of code. If you were to use this in serious (“production”?) software while some other code was running that needs any of the other 5 usable bits in that register, you will either interfere with whatever the other code was doing, or disable it entirely. Neither is likely to be what was intended. My recollection of the minutiæ of 6502 instructions is hazy, but I believe that:
lda #$b0 ; set Z80 mode sta $d505 ; this instruction deactivates 8502 and jumps by Z80 PC to $ffee
…should in some use-cases be replaced by something like:
LDA #$FE ; bitmask to set processor selection bit to 0=Z80 AND $D505 ; disable 8502, resuming Z80 execution where it left off (usually at $FFEE) Can anyone confirm that I did that right? Until I got my C128 I didn’t even own a machine language monitor, never mind an actual assembler (well, not one where I had any way to get the object code into a Commodore, anyway), so my knowledge in this area, unfortunately, tends to be mostly theoretical.
|
|
|
Post by gsteemso on Sept 21, 2014 23:39:10 GMT
Really don't see problem to rewrite Z80 code to use subroutine, but I see not reason why - please explain it me better. I think I know this one. When you switch to or from Z80 mode, the process of so doing does not write a return address to the stack — it just toggles a line coming out of the MMU, such that whatever CPU has just become active resumes execution at wherever its Program Counter was pointed (as I understand matters, this would usually be in the OS routine intended by Commodore to handle the switch). Thus, if you end with any type of “return to stacked address” instruction, a value is popped from the stack that was never placed there in the first place, sowing the seeds of chaos and confusion.
|
|