• Bit 64

  • by jwhoag

Commodore-related project and thoughts I have worked on

Apr
18

"RS-232" nuts

Gripes and other information about the madness underlying RS-232 on a C64

 

So obviously Commodore didn't put any rational thought into serial communication.  Communication at the pitiful rate of 2400 baud doesn't work reliably, let alone the grand dreams of 19200 listed in the PRG.  So it almost seems fitting that the infrastructure around serial "RS-232" communication is just as pathetic.
 
To do communication over an RS-232 connection, you must first open a channel on device 2.  Opening a channel is a fine idea, but the C64 implementation is just bad.  I'm not going to go into all the details of how to do this because you can read it for yourself in the PRG (pg 348).  When the C64 executes the OPEN statement it allocates two 256-byte buffers, one for sending and one for receiving.  These buffers get allocated at the top of usable BASIC memory.  So far, so good.  Here's where the bad news starts.
 
Strings start at the top of BASIC memory.  Does this sound familiar?  Why yes, the RS-232 buffers are here too.  So the architects of C64 BASIC decided that opening an RS-232 channel was such a serious undertaking that all variables must be cleared as part of the OPEN statement.  In essence, their method of ensuring that strings did not get corrupted was to completely and silently destroy them--along with all the other variables, and the stack as well.  To be fair, the PRG does include a small warning about this.  What this means is that you will need to open your RS-232 channel as one of the very first things in your program, and it can't be in a subroutine.
 
Here is some undocumented/underdocumented information that is really important if you have some machine language routines or sprite data or some other essential stuff that you want protected from the ravages of BASIC and RS-232 buffers:
 
OPEN moves the Top of Basic (55/56) and Top of OS (51/52) pointers down in memory by 512 bytes, and places the RS-232 Receive buffer at the new Top of OS and the RS-232 Transmit  buffer 256 bytes above that.  The buffer pointers are at:
  247/248: receive
  249/250: transmit
 
When you CLOSE the RS-232 channel, the buffer pointers are both set to 0, and the TOB/TOOS pointers are each incremented by 512, ostensibly to return them to their original values.
 
You may also specify your own buffer locations.  To do this, simply set the Rx and Tx buffer pointers to your desired locations immediately before calling OPEN.  When the OPEN statement sees non-zero values in these pointers, it will simply use them as-is without changing them or the TOB/TOOS pointers.  However, in this case, beware CLOSE!  The C64 does not remember that you set your own values, so it will do its normal thing and set them to 0, and then blindly increment the TOB/TOOS pointers!  That second part will likely cause very nasty problems.  In this case, you will need to maually return those pointers to the desired values and do another clr.
 
Since all variables get cleared upon the CLOSE command, typically the only time you'll ever want to close an RS-232 channel is at the very end of your program.  Like OPEN, it can not be executed from a subroutine, or you will get a ?Return without gosub error, since the stack is cleared as well.
 
Often it is customary to move the top of BASIC lower in memory and put your nuggets above all the commotion.  Here's a quick example.  Normally, TOB & TOOS are both set to $A000.  The names are slightly misleading because they actually point to the address after the top.  $9FFF is the last byte in the RAM are before BASIC ROM starts at $A000.  Let's say we want to reserve some extra space at the top of memory for some machine language routines.  We'll put those at $8000, but we want the RS-232 buffers to go at $9E00 and $9F00 (their usual positions).  Assuming we are starting from the normal pointers, we can do the following:
  poke 56, 128: poke 644,128:clr  | this sets TOB and TOOS to $8000 and the CLR adjusts a number of other pointers to match
  poke 248, 158 :poke 250, 159 :open 2,2,3   |this sets RsRx buf to $9E00, RsTx buf to $9F00, and opens the channel
 
We can get by without POKEing the low bytes of these pointers because we want them to be zero, and they already are (unless you've done some thing with them already!)
 
That does the trick.  Just remember that when you close the channel, you'll need to reset the TOB/TOS pointers to $8000 and clr again quickly, before anything bad can happen.  This all assumes you are using the BASIC OPEN command.  If you call the Kernal version of OPEN and CLOSE, things get uglier.  You'll need to do additional research if you plan to do that.
Since strings also use the So obviously Commodore didn't put any rational thought into serial communication.  Communication at the pitiful rate of 2400 baud doesn't work reliably, let alone the grand dreams of 19200 listed in the PRG.  So it almost seems fitting that the infrastructure around serial "RS-232" communication is just as pathetic.
 
Opening an RS-232 channel: To do communication over an RS-232 connection, you must first open a stream on device 2.  Opening a stream is a fine idea, but the C64 implementation is just bad.  I'm not going to go into all the details of how to do this because you can read it for yourself in the PRG (pg 348).  When the C64 executes the OPEN statement it allocates 2 256-byte buffers, one for sending and one for receiving.  These buffers get allocated at the top of usable BASIC memory.  So far, so good.  Here's where the bad news starts.
 
Since strings also use the 

Leave a Comment

You must be signed-in to post comments.

Responses

S0RC3R0R 4/21/2013

Is this what is happening when I load and SYS 49152 v-1541.38k and then load and SYS 36864+00 and BOOM!?!???

- S0R

jwhoag 5/6/2013

It is possible, S0rc3r3r. I don't know what v-1541 does exactly, or why its 38k would act differently than the 2400 in that respect.

AgentFriday 5/9/2013

Essentially, there is never any reason to close an RS-232 channel...

What commodore SHOULD have done is simply pre-allocate the RS-232 buffers above OS and then never touch them. Variables would be preserved and you'd rarely ever notice the loss of .5 K of memory. IF you really needed the extra 512 bytes, the pointers could be moved manually, and it would not cause a problem because you wouldn't be using RS-232.