Porting CP/M to the VIC-20: memory map questions
Moderator: Moderators
-
- Vic 20 Newbie
- Posts: 6
- Joined: Tue Apr 18, 2023 5:21 am
- Website: http://cowlark.com
- Location: zurich
Porting CP/M to the VIC-20: memory map questions
So I have a CP/M port to the 6502. I've got support for the PET, C64 and X16 (among others), so I thought it'd be nice to add support for the VIC-20 too to complete the set. https://github.com/davidgiven/cpm65
I'm planning on targeting a fully expanded machine. The BDOS and CCP (essentially the CP/M kernel) will live in bank 5, at 0xa000.
There are two conflicting design requirements: firstly, I need as much contiguous RAM as possible. It doesn't matter where, but it does need to be contiguous. The CP/M-65 assembler needs about 20kB just to load --- it's written in C. Secondly, I need a screen which is at least 40 columns.
IIUIC: to get 40x12 I have to use a soft font in high resolution mode. This means on the VIC-20 that I need to relocate the character map somewhere in low memory. Except, the VIC chip can only see on-board memory banks, so it's limited to the 1kB at 0x0000-0x0400 and the 4kB at 0x1000-0x2000. That's problematic. I can put the screen at 0x0200 and the character map at 0x1000, but this divides the memory into two. I get 0x1800-0x8000 as my working area. That's 26kB, which is acceptable, but everything from 0x0300 to 0x1000 is wasted.
To get 40x24 I need to use double-height characters. This doubles the size of the character map. Luckily the screen data remains the same size (240 bytes). I now get 0x2000-0x8000 as my working area, which is only 24kB.
Is there anything I've missed here? Are there any cunning tricks to let me place the character data elsewhere?
I'm planning on targeting a fully expanded machine. The BDOS and CCP (essentially the CP/M kernel) will live in bank 5, at 0xa000.
There are two conflicting design requirements: firstly, I need as much contiguous RAM as possible. It doesn't matter where, but it does need to be contiguous. The CP/M-65 assembler needs about 20kB just to load --- it's written in C. Secondly, I need a screen which is at least 40 columns.
IIUIC: to get 40x12 I have to use a soft font in high resolution mode. This means on the VIC-20 that I need to relocate the character map somewhere in low memory. Except, the VIC chip can only see on-board memory banks, so it's limited to the 1kB at 0x0000-0x0400 and the 4kB at 0x1000-0x2000. That's problematic. I can put the screen at 0x0200 and the character map at 0x1000, but this divides the memory into two. I get 0x1800-0x8000 as my working area. That's 26kB, which is acceptable, but everything from 0x0300 to 0x1000 is wasted.
To get 40x24 I need to use double-height characters. This doubles the size of the character map. Luckily the screen data remains the same size (240 bytes). I now get 0x2000-0x8000 as my working area, which is only 24kB.
Is there anything I've missed here? Are there any cunning tricks to let me place the character data elsewhere?
Re: Porting CP/M to the VIC-20: memory map questions
With a 160x192 mode you can get 40x24 chars. This fits in the 4K-area from $1000-$1fff. Use chars 16 to 255 at $1000 and start the character-RAM at $1100. This has been the standard-setup and has been used by MINIGRAFIK i.e.
Otherwise you are correct. You cannot get more than 24K contiguos RAM with 160x192 graphics.
Otherwise you are correct. You cannot get more than 24K contiguos RAM with 160x192 graphics.
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Porting CP/M to the VIC-20: memory map questions
First of all, welcome to Denial! 
Do you see any chances to strip seldom used features from the assembler to increase free space at least a little bit?

For more than just text display you would have to provide a 'shadow' text buffer though, which you could however place in the $0400..$0FFF address range and which thus would not deduct from your 24K TPA.
You should also keep in mind that the RESET, IRQ and NMI vectors are fixed in the KERNAL ROM, the addresses $0314..$0319 hold RAM-based vectors for the 2nd-level IRQ, BRK and NMI handlers and the RESET routine checks for an autostart signature at $A000.
You find some more details in the sticky post "VIC-20 Memory Layout".
Greetings,
Michael

The assembler would need to be completely file based, i.e. read source from file on disk, assemble to file on disk. Even so, this does not leave much room for the symbol table which ideally should reside in RAM.hjalfi wrote:The CP/M-65 assembler needs about 20kB just to load --- it's written in C.
Do you see any chances to strip seldom used features from the assembler to increase free space at least a little bit?
You might want to take a look at my soft 40 column solution for MINIGRAFIK. The routines have been optimized for fast output (even from BASIC!) and always draw complete text lines instead of just single characters. Below is the built-in character set, which I already chose to be ASCII, not PETSCII, as the former covers 99%+ of available text body. The drawn glyphs 'live' on a bitmap and I can draw any graphical decoration besides the text that I want, making the 'graphical' characters of PETSCII redundant:Secondly, I need a screen which is at least 40 columns. [...] To get 40x24 I need to use double-height characters. This doubles the size of the character map. Luckily the screen data remains the same size (240 bytes). I now get 0x2000-0x8000 as my working area, which is only 24kB.

For more than just text display you would have to provide a 'shadow' text buffer though, which you could however place in the $0400..$0FFF address range and which thus would not deduct from your 24K TPA.
As you have correctly noticed, it is only the internal RAM and the character ROM which the VIC chip can access (the colour RAM goes over an extra 4 bit data path and wouldn't anyhow be usable for graphics data anyway). The memory layout is fixed, so you are set with the 24K TPA in $2000..$7FFF.Is there anything I've missed here? Are there any cunning tricks to let me place the character data elsewhere?
You should also keep in mind that the RESET, IRQ and NMI vectors are fixed in the KERNAL ROM, the addresses $0314..$0319 hold RAM-based vectors for the 2nd-level IRQ, BRK and NMI handlers and the RESET routine checks for an autostart signature at $A000.
You find some more details in the sticky post "VIC-20 Memory Layout".
Greetings,
Michael
-
- Vic 20 Newbie
- Posts: 6
- Joined: Tue Apr 18, 2023 5:21 am
- Website: http://cowlark.com
- Location: zurich
Re: Porting CP/M to the VIC-20: memory map questions
I've decided to go for a 40x24 screen even though it uses the extra RAM. The implementation was easy, but it does seem to be creakingly slow. Luckily I've figured out how to do half-step scrolling mostly in hardware; I will need to shuffle the bytes in the screen RAM but not in the bitmap. We'll see if this leaves enough space for the assembler...
Unfortunately right now I'm fighting IEC code. I've finally gotten the tx code working, so I can send commands to the 1541 and it's responding, but it's locking up when trying to actually read data back again. I suspect something in the bus turnaround timing.
One of the problems I'm having is that I'm developing with VICE, which doesn't run the drive and the computer in lockstep. After getting MAME working, apparently neither does that. Also, MAME and VICE fail in different ways! I think the only thing to do now is to cut-and-paste the VIC-20 ROM routines into my own code and see whether _that_ works. The real IEEE-488 bus on the PET was far less trouble...
Unfortunately right now I'm fighting IEC code. I've finally gotten the tx code working, so I can send commands to the 1541 and it's responding, but it's locking up when trying to actually read data back again. I suspect something in the bus turnaround timing.
One of the problems I'm having is that I'm developing with VICE, which doesn't run the drive and the computer in lockstep. After getting MAME working, apparently neither does that. Also, MAME and VICE fail in different ways! I think the only thing to do now is to cut-and-paste the VIC-20 ROM routines into my own code and see whether _that_ works. The real IEEE-488 bus on the PET was far less trouble...
Re: Porting CP/M to the VIC-20: memory map questions
This doesn't happen on real hardware either, the IEC protocol is designed for that.
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Porting CP/M to the VIC-20: memory map questions
My text display routines effectively do around 6000 characters/second and can scroll 30 lines/second, both of which I think is not particularly bad. The scrolling is software only, one big unrolled loop over all columns.hjalfi wrote:I've decided to go for a 40x24 screen even though it uses the extra RAM. The implementation was easy, but it does seem to be creakingly slow. Luckily I've figured out how to do half-step scrolling mostly in hardware; I will need to shuffle the bytes in the screen RAM but not in the bitmap.
If you do hardware scrolling by remapping the text screen, that probably 'costs' you one or two text lines, as you will need these to cover up the workings of the vertical scroll register. I wonder if you perchance did a row-wise arrangement of the screen codes, which results in a more complicated address layout for the bitmap. The column-wise arrangement really is advantageous here.
srowe already wrote about this - demanding lock-step operation is not backed by what you have on real hardware. You have two CPUs, the drive CPU running at 1.00 MHz, the computer CPUs running at different frequencies spanning the range from ~0.9 MHz (264 PAL 7501 in 'slow' mode) up to ~2.1 MHz (128 NTSC 8502 in 'fast' mode). VICE does its best to interleave the operations (provided, the 'drive no idle' option is active), so both CPUs advance their instruction streams corresponding to their relative frequencies. Otherwise most faster bus protocols would fail (JiffyDOS for example synchronises only once per byte and then relies on a strict 10 µs 2-bit time, with NOPs inserted into the transfer code at strategic places).Unfortunately right now I'm fighting IEC code. [...]
The standard IEC protocol is clocked by the talking side. As soon as the listener signals it's ready for the next byte, it must be able to follow all CLOCK signal edges, latch the DATA input bits and do an acknowledge on the DATA line upon the last bit sent. If the listener is too slow doing the latter, the talking side will flag an error.
IMO, duplicating the KERNAL IEC code within your BIOS mostly costs you memory, without anything in return. Anything you'd need to access the disc is already present within the KERNAL ROM and the drive CBM DOS. Unless you implement a faster bus protocol, that memory could instead be used to add other functionality to BDOS or resident functions to CCP.
(If you feel above paragraph somewhat goes against a purist viewpoint, you are in good company: even the C128 CP/M used routines in the 128's KERNAL to access the disk drives

-
- Vic 20 Newbie
- Posts: 6
- Joined: Tue Apr 18, 2023 5:21 am
- Website: http://cowlark.com
- Location: zurich
Re: Porting CP/M to the VIC-20: memory map questions
It lives!

This is using all three memory areas. 0x0200-0x1000 contains the BIOS, which has got all the platform-specific stuff in it. 0xa000-0xc000 contains the BDOS and CCP (with 0x700 bytes free for drivers, if that ever happens). 0x2000-0x8000 is the user TPA of 26kB. This is sufficient to run decent-sized programs and assemble source files up to about 14kB (the assembler uses between 1/3 to 1/2 the size of the source file in RAM). Naturally it's all excruciatingly slow due to the performance of the IEC protocol. I find it hard to believe that someone at Commodore looked at this and said 'this is fine, let's ship it'...
I did eventually realise that to do line-by-line scrolling I'd have to sacrifice two horizontal lines on the screen, so I didn't both and now the screen scrolls two lines at a time. Performance is fine.
Regarding using the kernel IEC routines: that is, in fact, what the C64 port of this does. The problem is the zero page layout. The C64 puts the IEC workspace up near the top of zero page, but the VIC-20 puts it right in the middle, which halves the amount of contiguous zero page. The routines also unconditionally enable interrupts, which mean that I also have to have the interrupt vectors in page 0x300. As I have quite a lot of unusable free memory it actually saves memory to reimplement these routines.
I would like to add support for a fastloader at some point; probably the JiffyDOS one as it seems the best supported and not many fastloaders have write support. I'd really prefer a properly open-source one which can be loaded at run-time, though.
Edit: Forgot to post a link to the disk images; note that some programs here don't work properly due to an llvm-mos bug which is fixed upstream, but I'm waiting for a release. https://github.com/davidgiven/cpm65/releases/tag/dev

This is using all three memory areas. 0x0200-0x1000 contains the BIOS, which has got all the platform-specific stuff in it. 0xa000-0xc000 contains the BDOS and CCP (with 0x700 bytes free for drivers, if that ever happens). 0x2000-0x8000 is the user TPA of 26kB. This is sufficient to run decent-sized programs and assemble source files up to about 14kB (the assembler uses between 1/3 to 1/2 the size of the source file in RAM). Naturally it's all excruciatingly slow due to the performance of the IEC protocol. I find it hard to believe that someone at Commodore looked at this and said 'this is fine, let's ship it'...
I did eventually realise that to do line-by-line scrolling I'd have to sacrifice two horizontal lines on the screen, so I didn't both and now the screen scrolls two lines at a time. Performance is fine.
Regarding using the kernel IEC routines: that is, in fact, what the C64 port of this does. The problem is the zero page layout. The C64 puts the IEC workspace up near the top of zero page, but the VIC-20 puts it right in the middle, which halves the amount of contiguous zero page. The routines also unconditionally enable interrupts, which mean that I also have to have the interrupt vectors in page 0x300. As I have quite a lot of unusable free memory it actually saves memory to reimplement these routines.
I would like to add support for a fastloader at some point; probably the JiffyDOS one as it seems the best supported and not many fastloaders have write support. I'd really prefer a properly open-source one which can be loaded at run-time, though.
Edit: Forgot to post a link to the disk images; note that some programs here don't work properly due to an llvm-mos bug which is fixed upstream, but I'm waiting for a release. https://github.com/davidgiven/cpm65/releases/tag/dev
Re: Porting CP/M to the VIC-20: memory map questions
You're welcome to use zippy, my implementation of JiffyDOS for the VIC, it's GPLv3
https://eden.mose.org.uk/gitweb/?p=zippy.git;a=summary
Simon
- polluks
- Vic 20 Amateur
- Posts: 45
- Joined: Sat Apr 29, 2017 4:53 pm
- Website: http://www.bilskaja.de
- Location: Germany
- Occupation: FI
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Porting CP/M to the VIC-20: memory map questions
Not sure where you got that info from. BASIC and KERNAL of VIC-20 and C64 are very similar, and besides the C64 using $00/$01 for the CPU port, the layout of the zero page ($00..$FF) is exactly the same: $00(or $02)..$8F 'belong' to BASIC and $90..$FA 'belong' to the KERNAL; with $FB..$FE free for users, and $FF being in use during float<->ASCII conversions and thus effectively also allocated for BASIC.hjalfi wrote:Regarding using the kernel IEC routines: that is, in fact, what the C64 port of this does. The problem is the zero page layout. The C64 puts the IEC workspace up near the top of zero page, but the VIC-20 puts it right in the middle, which halves the amount of contiguous zero page. [...]
In $90..$FA is where the KERNAL I/O mostly does its things for keyboard, screen, tape, IEC, RS232; with some of the addresses shared between tape, IEC and RS232. Anything that could in the widest sense be regarded as implementation of a language and which only relies on KERNAL routines (i.e. does not use any of the routines in the BASIC interpreter) can use the lower part of the zero page as it pleases.
From what I have gathered while taking a peek with the VICE monitor, you are putting some unrelated data there. When you kick out the KERNAL on the VIC-20, at least $0314..$0319 need to be kept alife by pointing them to viable replacement routines for IRQ, BRK and NMI.The routines also unconditionally enable interrupts, which mean that I also have to have the interrupt vectors in page 0x300.
...
Two questions: as your CP/M loader supports code relocation, is it viable to "cross-assemble" *.ASM files for the VIC-20 on the C64 instead? Also, is there a tool available to access the CP/M file system within a *.d64 image from the PC?
-
- Vic 20 Newbie
- Posts: 6
- Joined: Tue Apr 18, 2023 5:21 am
- Website: http://cowlark.com
- Location: zurich
Re: Porting CP/M to the VIC-20: memory map questions
(Thanks, Google, you ate the notification email for this message...)
Re the memory map: it's possible I got it confused with the PET. I've been staring at way too many very similar Commodore memory maps recently. Also, I completely forgot about NMI handling. I see that on the VIC-20 the RESTORE key is wired directly to the NMI line. Luckily it looks like I can disable it.
Re cross-assembling binaries: yes. CP/M-65 binaries are completely generic, and the same binary will run on any port --- that now includes the Atari 800, BBC Micro family, VIC-20, C64, PETs 4032, 8032 and 8096, and Apple IIe. No Oric yet. The filesystem is a completely generic cpmfs image, accessible with cpmtools. The corresponding diskdefs file is here: https://github.com/davidgiven/cpm65/blo ... r/diskdefs
Re the memory map: it's possible I got it confused with the PET. I've been staring at way too many very similar Commodore memory maps recently. Also, I completely forgot about NMI handling. I see that on the VIC-20 the RESTORE key is wired directly to the NMI line. Luckily it looks like I can disable it.
Re cross-assembling binaries: yes. CP/M-65 binaries are completely generic, and the same binary will run on any port --- that now includes the Atari 800, BBC Micro family, VIC-20, C64, PETs 4032, 8032 and 8096, and Apple IIe. No Oric yet. The filesystem is a completely generic cpmfs image, accessible with cpmtools. The corresponding diskdefs file is here: https://github.com/davidgiven/cpm65/blo ... r/diskdefs