Tuesday, October 30, 2012

Super Forth 64 - RS 232 console.


Today I managed to connect to my C64 running Super Forth 64 from a PC computer via RS-232 with Hyper Terminal program.

To do so, first we need to open logical file to user port's RS-232:

10 2 10 " {CTRL-H}" OPEN

NOTE: CTRL-H represents code CHR$(8) which sets the speed of RS-232 interface to 1200 baud. To connect with 300 baud, use CTRL-F (CHR$(6)).

Assuming that PC computer is connected to C64's user port via RS-232's COM1 and that C64's user port is equipped with appropriate interface, on the PC side, open Hyper Terminal session to COM1 at 1200 baud 8N1.

After opening logical file, we need to redirect I/O to that file. On the C64 side type:

10 OUTLFN !
10 INPLFN !

NOTE: After output redirection (typing in 1st line above and pressing Return), C64 console will no longer show output. Instead it now should appear on the Hyper Terminal's screen. After entering 2nd line, enable CAPS-LOCK on the PC and perform all FORTH session interaction from Hyper Terminal (HT) from now on. 

Commodore 64 is now a Super Forth 64 host, and PC with HT is a client session. Not all operations are possible via such session. E.g: user will be unable to use screen editing facility. Also, character codes are not fully compatible between PC and C64, so all C64 responses will be in capital letters. If there is any text using mixed caps coming from C64, the letters that'd be visible as capital letters on C64 will not come right on the HT side. 

C64 screen after redirection to RS-232 just sits quietly while interaction is performed from HT on a PC.
HT/PC side.

Thanks for visiting my blog.

Marek Karcz
10/30/2012

Sunday, October 21, 2012

Super Forth 64 - interrupt driven screen clock.



Programming routines running in interrupts can be tricky under FORTH. In this article I describe the design and code of 12-hour text mode screen clock running in interrupt. The system of my choice was Super Forth 64 by Elliot B. Schneider. That was the first FORTH system I have had experience with and I think it is a good choice to develop applications and operating systems on C64 because of the powerful extensions that SF-64 offers. In particular a very well defined assembler vocabulary as well as C64 specific hardware support (graphics, sprites and sound).

  1. Interrupt driven code.

The tight time constraints of interrupt handler make the assembler an easy choice language for this kind of task. The single “frame” of the clock routine must complete within 1/60 of a second. FORTH is fast, however still an interpreted language. Therefore I decided to code IRQ handler using Super Forth's assembler vocabulary. Before I coded the clock, I needed some helper definitions and variables. To minimize code size and maximize speed, I decided to use an array of clock digits, hard coded in a 120 bytes long vector, that would hold an array of strings: “00”, “01”, “02” … “58”, “59”.
The strings representing current hours, minutes and seconds would be then selected from the table by indexing with clock counters.

FORTH DEFINITIONS
: VECTOR ( n --- ADDR )
  CREATE ALLOT
  DOES> +
;
59953 CONSTANT IRQROM ( ADDRESS OF STANDARD IRQ IN ROM )
2 VECTOR IRQCLKPTR ( POINTER TO CLOCK ROUTINE – NEW ORQ ADDRESS )
2 VECTOR IRQROMPTR ( POINTER TO STANDARD IRQ IN ROM )
IRQROM 0 IRQROMPTR ! ( SET POINTER TO ROM IRQ )
120 VECTOR GMS ( VECTOR WITH CLOCK “DIGITS” )
48 0 GMS ! ( SET “00” )
48 1 GMS !
48 2 GMS ! ( SET “01” )
49 3 GMS !
48 4 GMS ! ( SET “02” )
50 5 GMS !

(NOTE: continue initialization of GMS vector until “59”)

53 116 GMS ! ( SET “58” )
56 117 GMS !
53 118 GMS ! ( SET “59” )
57 119 GMS !

VARIABLE LICNIK ( COUNTER, SORRY - I AM POLISH :-) )
VARIABLE GODZINA ( HOURS )
VARIABLE MINUTA ( MINUTES )
VARIABLE SEKUNDA ( SECONDS )

( INITIALIZE VARIABLES )
0 LICNIK !
2 GODZINA !
0 SEKUNDA !

OK, I am done with helper vectors and variables. Now there is time to write some code.
In SF-64 system the assembler routine starts with the word CODE followed by the name of the routine. The assembler dictionary in SF-64 is quite sophisticated. Thanks to the general dictionary based architecture, the labels used in traditional assembler code are not needed here. We have branch structures (IF, THEN,) as well as loop control words that allow to write structurally looking code without the need for jumps and labels. In a way, the SF-64 assembler is like a macro turbo-assembler that compiles the code as user types it or as it is being read from the input stream.

My interrupt driven clock routine is presented below:

CODE IRQCLOCK
   ( UPDATE COUNTERS, CALLED EVERY 1/60 OF SECOND )
   LICNIK INC,
   LICNIK LDA,
   60 # CMP,
   0=
   IF,
      0 # LDA,
      LICNIK STA,
      SEKUNDA INC,
      SEKUNDA INC,
      SEKUNDA LDA,
      120 # CMP,
      0=
      IF,
         0 # LDA,
         SEKUNDA STA,
         MINUTA INC,
         MINUTA INC,
         MINUTA LDA,
         120 # CMP,
         0=
         IF,
            0 # LDA,
            MINUTA STA,
            GODZINA INC,
            GODZINA INC,
            GODZINA LDA,
            26 # CMP,
            0=
            IF,
               2 # LDA,
               GODZINA STA,
            THEN,
         THEN,
      THEN,
   THEN,
   ( UPDATING COUNTERS DONE, NOW PRESENTATION )
   GODZINA LDX, ( USE GODZINA AS INDEX IN GMS VECTOR )
   0 GMS ,X LDA, ( LOAD DIGITS FOR CURRENT HOUR )
   1056 STA, ( POKE DIRECTLY TO SCREEN MEMORY )
   INX, ( IN THE HOURS FIELD )
   0 GMS ,X LDA,
   1057 STA,
   58 # LDA, ( TAKE COLON CHARACTER CODE ':' )
   1058 STA, ( POKE TO THE SCREEN MEMORY, NOW – HH:_____ )
   MINUTA LDX, ( REPEAT PROCEDURE FOR MINUTES )
   0 GMS ,X LDA,
   1059 STA,
   INX,
   0 GMS ,X LDA,
   1060 STA,
   58 # LDA,
   1061 STA, ( NOW ON SCREEN – HH:MM:__ )
   SEKUNDA LDX, ( … AND FOR SECONDS )
   0 GMS ,X LDA,
   1062 STA,
   INX,
   0 GMS ,X LDA, ( PRESENTATION UPDATE COMPLETE )
   1063 STA, ( NOW ON SCREEN (NORTH-EAST) – HH:MM:SS )
   IRQROM JMP ( CONTINUE TO ROM IRQ HANDLING ROUTINE )
END-CODE
( SETUP THE NEW IRQ POINTER TO OUR CLOCK ROUTINE )
FIND IRQCLOCK @ 0 IRQCLKPTR !

Now we need a word defined that would allow to set a new IRQ vector. 

Remember the algorithm?


  • Mask interrupts (disable). 
  • Set new IRQ vector.
  • Unmask interrupts (enable).

CODE SET-NEWIRQ ( LO HI --- )
   SEI, ( MASK INTERRUPTS )
   BOT LDA, ( READ BOTTOM OF STACK WHERE LO BYTE IS )
   788 STA, ( PUT IN THE C64'S IRQ VECTOR - LO )
   SEC LDA, ( READ NEXT STACK BYTE WHERE HI BYTE IS )
   789 STA, ( PUT IN THE C64'S IRQ VECTOR – HI )
   CLI, ( UNMASK INTERRUPTS )
   NEXT JMP, ( CONTINUE TO THE NEXT FORTH WORD IN QUEUE )
END-CODE

  1. Control routines.

Now that I am done with low level code, time to define words that would allow the user to set the clock and turn it on and off. This is the easy part:

FORTH DEFINITIONS
: SET-IRQCLOCK
  SP! CR
  .” HOURS (1-12)? “ INPUT 2 * GODZINA ! CR
  .” MINUTES (0-59)? “ INPUT 2 * MINUTA ! CR
  .” SECONDS (0-59)? “ INPUT 2 * SEKUNDA ! CR
  .” CLOCK IS SET “ CR SP
;

: IRQCLOCK-ON
  SET-IRQCLOCK
  ( LEAVE ON STACK HI/LO BYTES OF NEW IRQ ADDRESS )
  1 IRQCLKPTR C@ 0 IRQCLKPTR C@
  SET-NEWIRQ
;

: IRQCLOCK-OFF
  ( LEAVE ON STACK HI/LO BYTES OF ROM IRQ ADDRESS )
  1 IRQROMPTR C@ 0 IRQROMPTR C@
  SET-NEWIRQ
;

This is pretty much it. It is amazing how efficient programming in FORTH can be. I love it.

And now some screens for non-believers :-)


Code finished loading/compiling.
Setting up the clock.
Clock is running (upper right corner).


Thank you for reading.


Marek Karcz
10/22/2012

Tuesday, October 16, 2012

CP/M on a C64 - fun and learning.


Hello again.

What I learned so far about CP/M for C64 by practical application:

  1. Commodore 64 will not support 2 disk drives (unless you patch it with simple BASIC program, which updates CP/M disk for 2 drive support).

    Even though bios configuration program seems to have the option to switch between 1 and 2 disk drives mode, when I switched to 2 drives mode, saved the configuration on disk and re-booted with 2 disk drives connected to my C64, attempts to switch to drive B: ended in BDOS error. My 2nd drive is 1571, however AFAIK, it works by default in 1541 mode unless explicitly reprogrammed to use extra features.

There is a remedy though. With the help of a BASIC program found here: URL, I patched CP/M disk so that C64 now is able to support 2 disk drives under CP/M.
You need to type in the BASIC program, save it on the disk (but not a CP/M disk, just your regular C64 storage for backup purposes) and then switch the disk for a CP/M one into drive 8 and run the BASIC program you just entered. Next time you need to patch up a CP/M disk, load that program from your backup, switch disk for a CP/M one and run the program again. After booting up CP/M, run your CONFIG.COM program to change the number of drives to 2 and save the current I/O setup to disk (option #6), then exit to CP/M (option #7), insert valid CP/M disk to drive B: (9) and test the functionality:

A> dir B:

Config program.

Checking disk B: stats


  1. Changing the diskette in drive.
    Changing the diskette in drive without warm restart (CTRL-C or RUN-STOP) will switch that disk to R/O mode. User will be unable to make modifications to that drive until next warm restart. With that in mind, the disk in drive must be always CP/M type with c64boot procedure on track 1, sector 5.

OK, enough learning. Now there is time for some fun.
What would be a computer without a game? Just a piece of junk, I say! Fortunately, many popular games were ported to CP/M platform. Most of them are text mode based games, due to nature of CP/M (no built in graphical support, generally incompatible across hardware platforms). However it does not matter much, because in the CP/M era, many popular games were text based. Good examples are Infocom's adventures or a famous StarTrek game (originally written in BASIC AFAIK).

I successfully created C64 CP/M ZORK1 and ZORK2 game disks (google up "ctools by Jochen Metzinger" for transferring programs to C64/C128 CP/M disk images, can also create Commodore format CP/M blank disks - an awesome tool). Even though they were designed to work with 80 column mode, since there is no fixed ASCII art or elaborate ASCII screens that depend on fixed size, similar to famous Star Trek game, the ZORK adventures are perfectly playable on C64 under CP/M. I know there is no point of playing them under CP/M, since they were released for native C64, but it is not the point of this exercise.

I have been unable to run Star Trek game though. All the files fit on one disk (MBASIC.COM, STARTREK.BAS, TREKINST.BAS), however C64 leaves insufficient memory for MBASIC.COM to load STARTREK.BAS.

Zork1 game.

Zork2 game.

So far I have a very positive experience with CP/M for C64.

In the next episode: 80 column display emulation and perhaps some more programming examples.

Cheers!

Marek
10/16/2012

Sunday, October 14, 2012

CP/M on a C64 - Hello World



I think a good old “Hello World!” application is in order now in our quest of CP/M exploration.
Since I don't know the Z80 assembler (yet) nor the structure of the assembly program for CP/M I again turn to the internet for rescue.
I found one very good comprehensive explanation of how to use assembler compiler 'ASM' under CP/M system and an example of “Hello World!” application written in 8080 CPU assembly (which BTW is a subset of Z80's assembly). Here is the URL.

So, in short – to compile assembler code, saved on the disk under name HELLO2.ASM (I prepared that one with the CP/M's line editor: ED), you invoke CP/M command:

A> ASM HELO2






As a resut, the Intel HEX format file is generated along with PRN file: HELLO2.HEX, HELLO2.PRN

The PRN file is of no concern to us at the moment.
Now we need to convert Intel HEX file into CP/M executable. This is done with LOAD utility:

A> LOAD HELLO2

Above command will produce some information about resulting executable (.COM) in the form of first address, last address, bytes read and records written numbers. It will also create HELLO2.COM program on the disk as well.

Now type at the prompt the name of the program:

A> HELLO2

and enjoy the resulting message:

HELLO WORLD.



I think it is enough excitement for a moment. Go ahead and experiment with other CP/M BIOS functions, observe the results and learn if you want.

In the next episode - what I learned about CP/M so far and how I created my own C64 CP/M disk with Infocom's ZORK1 adventure game.

Stay tuned!

Marek
10/14/2012

Saturday, October 13, 2012

CP/M on a Commodore 64.


      I've always been intrigued by CP/M operating system although I've never used it before. I possessed some knowledge about it, mostly that it was Intel CPU and Z80 oriented and how the user interface looked like and that it was a disk OS and that a lot of good professional software has been created for it. At some time in the 90-s, when I was still active (read - every day) C64 user, I made an attempt to create operating system of my own, only to learn later that the principles I chose for my OS, how it was bootstrapped, the architecture of kernel and control program and UI were very similar to these of CP/M. I liked  CP/M because it provides structure and standardization that home computers needed so much, especially in the 70s and 80s era. The standardization we now possess and take for granted in the form of PC architecture did not exist at the time with the exception of mainframe computers and for home computers, CP/M filled the niche.

I recently acquired CP/M cartridge for C64 on eBay. A great opportunity to give that OS a try when I finally had hardware that could run it in its very historical, almost original form. I knew that C64's cartridge was somewhat infamous for not delivering exactly on its promise and that it had been discontinued shortly after it was offered in retail. However I believe much of the bad rap this piece of hardware got can be attributed to the fact that it was not user friendly, or to better put it (since not a lot of software or computer hardware in the day you could call "user friendly" anyway) - not easy to use. First and foremost, the main obstacle to get the promised software base was incompatible to CP/M standard Commodore's disk format. The other - slowness. The cartridge has Z80 CPU on board with some glue logic that allows for it to use C64's resources (RAM, VIC, peripherals, CPU bus in general) together with C64's CPU - 6510 (well, not together, they switch between each other using some register, but pretty much C64 is turned into a dual CPU machine). The design of the cartridge and timing considerations forced the Commodore engineers to retard the Z80 clock, so the computer did not run too fast in CP/M mode. Another problem with the cartridge, which manifested itself later in history is that it did not work well with later versions of C64 main boards, especially with C64-C, which can be probably attributed to some peripheral chips (like VIC II) that were "fixed" in that model. Since Commodore did not produce the CP/M cartridge anymore at that time, they did not bother to produce a fix.

First, I wanted to test somewhat if the cartridge itself is not "dead". Original cartridge was sold with CP/M disk, instruction manual and some teat program in BASIC, I am not sure if it was on the disk or to be typed in from instruction manual. Since the program is pretty short, I believe it could be distributed in the form of printed copy that user could type in and run to test the cartridge without booting up the CP/M disk. Since we live in internet era, a lot of information is widely available on the net. I started the google search and quickly found the page with test program listing. I inserted the cartridge into C64, typed in the test program, saved it on disk and ran it. It all seemed to work. The interesting note here - the test program seemed to work fine on C64-C model as well, it was the CP/M itself that I could not get to work on that one and had to turn to my older model - the bread bin C64 made in 1983.
OK, so the test has passed, time to check how the actual CP/M works. However I had no original disk. No worries, in this day and era anything in electronic format is at your fingertips. I found the images here. With the help of my X1541 cable and opencbm software I transferred my image. Loaded the disk to C64. Typed in:

LOAD"CPM",8
RUN

Moment of truth...(this is C64-C) the asterisks appeared on the screen, but stopped. The system hangs. I repeat, this time I get OS startup message and UI prompt, but attempt to type in anything hangs up computer again. The next try ends up in artifacts on the screen and hang-up as well. I switched to my older bread bin C64 and now we were in business. At the prompt:

A>

I typed:

A> DIR

pressed ENTER and the directory of files has appeared. I have successfully booted up CP/M in year 2012 on my C64.

The CP/M adventures will continue in following posts, please stay tuned...

Marek
2012/10/13