• Please review our updated Terms and Rules here

NEC V20: BRKEM, CALLN and RETEM

Ruud

Veteran Member
Joined
Nov 30, 2009
Messages
1,403
Location
Heerlen, NL
This is mainly meant for people who are familiar with the V20 8080 mode (or want to learn it). I hope they can correct my findings and/or add their own experiences.


I am trying to find out how to go from 8088 mode to 8080 mode and back when using a NEC V20. And this is the result so far.

BRKEM:

This is from the "User manual":

The BRKEM instruction starts the 8080 emulation mode.
It saves the contents of the PSW, PS, and PC, and resets
the MD flag to O. The segment base and offset values are
then loaded into the PS and PC registers respectively
from the interrupt vector table. The interrupt vector
number is specified by the immediate operand of the
BRKEM instruction.

This and various source code I found lead to these guide lines:
- Choose a free interrupt, like 80H (*)
- Choose a free segment of 64 KB of RAM. This depends purely on what you have running on your system but I personally think of the 64 KB at the end of the program.
- Load the CP/M part from disk into this segment. I think this should be something that fills the segment from 0000h up to 0FFFFH.
- Fill the interrupt segment part of the interrupt with the number of your segment.
- Fill the interrupt offset part with the address where the V20 should start to execute the 8080 code. I wonder if it can be a piece of RAM that can be overwritten by, for example, a CP/M program. In this way we free up some RAM.
- Fill DS with the value of the chosen segment as well.
- Make sure that the interrupt is enabled: STI.
- NASM/MASM/TASM don't know this typical V20 command so a macro has to be created for this instruction.
- Execute: BRKEM 80h

(*) The manual advises to reserve four interrupt vectors:

Vectors 32 to 255 are for general use. These vectors are
used for the four interrupt sources: 2-byte break, BRKEM,
CALLN instructions (during emulation), and INT input.

I have to find out yet what are meant with "2-byte break" and "INT input".


CALLN:

This command is used in 8080 mode.
- We need to reserve a free interrupt like 81H
- Fill the interrupt segment part of the interrupt with the number of your segment.
- Fill the interrupt offset part with the address where the V20 should start to execute the 8080 code for CALLN.
- I created my Z80 assembler so I can add the instructions CALLN and RETI. But I guess someone else has to create macros for these ones.
- Execute: CALLN 81h

CALLN is used to tell the V20 to execute 8088 code. That can range from putting a character on the screen to reading a file from disk into memory. These are pre-programmed tasks and the various codes in the registers tell the V20 what task to execute.
Various source code I saw so far mentioned that the 8088 code should be inside the CP/M segment as well. But I wonder: must it? What about doing a far jump to the segment next to this one and execute the code there? Would surely save memory and that would allow us to do nice tricks without having to worry about narrowing the available memory for CP/M itself.

I found two source codes using CALLN. What wondered me was that they used in fact two interrupts: one to handle BIOS things the other to handle BDOS things. Why should these been kept appart?


RETEM:

This command is used in 8080 mode and is meant to exit the 8080 (more or less) permanently. "More or less" because one of the source codes used RETEM to perform a warm boot. AFAIK a warm boot means reloading the CCP. After the CCP has been loaded, BRKEM has to be executed again. So beside the CCP, another piece of code has to be loaded, the piece that should be executed after BRKEM. Or should a pointer somewhere inside the CCP be enough? I have to find that out as well.


Please shoot :)
 
An addition to the CALLN part: the instruction RETI makes the V20 return to 8080 mode again.
 
Thank you, but this is the User Manual I mentioned above. I just hope you are willing to have a good look at it and give you comment, please.
 
I don't see what your confusion is. Section 8 in the manual explains it in great detail.
Your code should have exactly one BRKEM and your 8080 code one RETEM, Think of BRKEM/RETERM as open and close operations. If your 8080 code needs x86 servicing, it uses the CALLN instruction and the x86 code returns to emulation via RETI. Think of the CALLN as the same as a x86 BRK instruction.

I worked from an older version of the user's manual, but the content is the same.
 
OK, this is probably a case of "this is so obvious so I didn't mention it". The above you wrote was clear and indeed mentioned in the manual. But to execute these instructions, some steps have to be taken first, like reserving interrupt vectors for BRKEM and CALLN and how they should be used. I wrote down these steps so somebody with experience, like you, could have a look at them and tell me if they are OK or wrong.

I really hope that you have a look at them and can give me your opinion. Many thanks in advance!
 
22Nice selects the interrupt vector in four ways:

1. Uses the one specified by a command-line argument.
2. Uses the one specified by an environment variable
3. Searches for an unused vector pair starting with 80h (0000:0000 pointer)
4. If 1-3 fail, uses a preconfigured default (80h, 81h). (never got this far in 30+ years)
 
It might actually be the best idea to use the low vectors normally reserved for exception handlers. Ordinary application programs are free to take control of these (most run-time libraries do this at least for INT 00h), so anything in the background is guaranteed not to use them. And 8080 code can't generate exceptions at all, even when you would really want it to (invalid opcodes)!

Having separate vectors for BIOS/BDOS isn't required. Or even for BRKEM and CALLN, although that would require a complicated dance of init code running in 8080 mode with DS=0000, which would then change the interrupt vector and call back into native mode to set DS to its final value. Or perhaps a single handler that modifies itself, or detects in which mode it is currently running.

Before exiting to DOS, run RETEM so that the mode flag is locked again. Needing to use BRKEM to unlock it is not just there for obscurity: there exists code that loads the flag register with values where bit 15 is clear, which in the unlocked state would inadvertently enter 8080 mode and crash. I observed that this happens for example with the BIOS startup code on "Tidalwave" palmtops.
 
Yes, it's a lot simpler to have separate vectors. Possibly also for BIOS and BDOS calls, depending on how the code for those is implemented. Was just pointing out a theoretical possibility of how to reuse a single one for both entering 8080 mode and then calling back.

Also DOS reserves the INT 30h and 31h vectors for its CP/M compatibility hack (these aren't normal interrupt vectors, but a far jump instruction placed inside the IVT area, overwriting 5 bytes at that location). Would be another somewhat logical choice to use for an interface while the emulator is running.
 
Last edited:
In any case, V20 support after the 80286 era is a non-issue for me--there's no advantage for it, unless of course, you know of a, say, 30 MHz V20. Besides, V20 emulation won't run JRT Pascal 1.0 (check your NEC MicroNOTES).
Running under a V50 might be reasonable, however. However, I don't recall too many PCs using that MPU, though a few used the V40.

Thinking about it, I have a wall-wart powered V40 box originally used for receiving FAXes. Has a Teac 1.44M drive for storage, NS8473 FDC as well as the modem chip and parallel interface. The V40 has a UART internally. There's 256KB RAM with 256KB ROM. I suppose it could be jiggered to run CP/M in 8080 emulation mode. I suppose it could be fun. Maybe one day...
 
Last edited:
Of course the V20 is obsolete. So is CP/M. But having an x86 CPU run 8080 code natively is more interesting, I think, than doing the same in software emulation :)
 
It's all the same to me. Microcode vs. program emulation. Program emulation has the advantage of portability. If you have an 8088 or a Core I13 CPU, you're still good.
 
For maximum portability today, you'd write your emulator in JavaScript. Could possibly be made to run on an 8088 too - with a looooooooooooot of patience.

But that's kind of the antithesis of what this forum is about.
 
Of course the V20 is obsolete. So is CP/M. But having an x86 CPU run 8080 code natively is more interesting, I think, than doing the same in software emulation :)
That's the spirit!

There are various CP/M emulators around, some a zillion times faster than any original CP/M computer. I own a Commodore 128, Kaypro 4 and a Bondwell 14, so enough machines to run original CP/M if I feel the urge. But running CP/M as a complete OS on a PC has never been done AFAIK. And THAT intrigued me.
I already mentioned in other threads the V20-MBC. If this SBC can do it, I don't see any reason why a PC equipped with a V20/V30 cannot do it. It is just a matter of programming (I think).

About programming: that's tougher than I thought. Not the BRKEM etc. stuff but creating a BIOS that should start up the whole. I notice that I haven't worked with Z80 assembly for a long time. But I'm not dead yet and hope to live a long time :)
 
As long as you have to go to x86 mode for some BIOS functions, why not all of them? Gives you lots of x80 memory to play with. Here's what I wrote about 35 years ago.
 

Attachments

  • ebios.zip
    1.6 KB · Views: 8
I already mentioned in my first post that IMHO the V20 can run a part of the program outside the original CP/M segment. I don't understand everything, mainly the EMT part, but if I understand you correctly, almost everything is done in 8088 mode. And I love it, great idea!
- I'm better in 8088 assembly than Z80 or 8080
- It can save even more RAM in the original segment.
 
"emt" is just a CALLN that enters the address of the interrupt number in a table, so that it can be plugged when loading. The other aspect is that arguments regarding function type are placed in the two bytes following the CALLN, so they can be fetched by the 8088 code. I mean, if you have to go outside of 8080 mode to support various BIOS functions, why not put just as much as you can in 8088 memory making the BIOS footprint small? The cold boot address (in location 0) for 22Nice is FE03h. I ran into problems trying to make the BIOS only 256 bytes, but 512 seems to work with everything. As a matter of interest, everything after FEB0h is empty.

22Nice, could in theory, be modified to run CP/M BDOS and CCP, because there is a standard BIOS jump table.
It was mostly a matter of integration with the DOS environment. Why bother with CCP when you can use the much more powerful COMMAND.COM? And that leaves BDOS, whose functions can be mapped into DOS calls.
 
It is very interesting.

And what about turning HP 95LX (which has a V20 CPU) into a CP/M 2.2 (or CP/M 3.0) machine?
 
Back
Top