davidgiven / cpmish

An open source sort-of CP/M 2.2 distribution.

Home Page:http://cowlark.com/cpmish

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BBC BASIC hangs on emulators

jblang opened this issue · comments

When run on an emulator such as RunCPM or SIMH, BBC BASIC hangs when you attempt to RUN a program. The problem is that it's using the R (memory refresh register) as a random number seed, and emulators apparently just return 0 for this register instead of incrementing it like a real CPU does. In your sources, it will loop indefinitely as long as R is 0 so it will never run the program.

RUN0:   LD      SP,(HIMEM)      ;PREPARE FOR RUN
        LD      IX,RANDOM
RAND:   LD      A,R             ;RANDOMISE (CARE!)
        JR      Z,RAND
        RLCA
        RLCA
        LD      (IX+3),A
        SBC     A,A
        LD      (IX+4),A

I disassembled the official BBC BASIC Z80 binary and it is doing this slightly different. It still initializes the random seed form R but if it's zero, it just increments it to 1 and moves on.

l0ee1h:
	ld sp,(03de4h)		;0ee1	ed 7b e4 3d 	. { . = 
	ld ix,03df6h		;0ee5	dd 21 f6 3d 	. ! . = 
	ld a,r		;0ee9	ed 5f 	. _ 
	jr nz,l0eeeh		;0eeb	20 01 	  . 
	inc a			;0eed	3c 	< 
l0eeeh:
	rlca			;0eee	07 	. 
	rlca			;0eef	07 	. 
	ld (ix+003h),a		;0ef0	dd 77 03 	. w . 
	sbc a,a			;0ef3	9f 	. 
	ld (ix+004h),a		;0ef4	dd 77 04 	. w . 

I am going to fix this in my fork of BBC BASIC and I thought you may want to do the same.

I guess the sources R.T. Russell gave you don't exactly match the official binary. Another difference is between your patch.z80 file and the BBCDIST.MAC file distributed with the official binary. The timer code you had to comment out in your version doesn't exist in the BBCDIST.MAC file, and there are other minor differences.

BTW, my fork is available here: https://github.com/jblang/bbcbasic-z80. I have modified it to assemble with z88dk's z80asm. I plan to eventually add support for my TMS9918A video card: https://github.com/jblang/TMS9918A/

Ooh, interesting. The version I got was a simple dump from the only source code remaining, so it's plausible that it's not the same as the distribution version. I should certainly apply that fix. I've just tried it in cpmish's own emulator and, yes, it doesn't work.

Do you think it's worth replacing the BBCDIST.MAC file with the distribution one?

Well, neither one uses ANSI escape codes for the CLS or TAB functions, which is what modern terminal emulators would expect. For CLS, both versions are using different control sequences from some unknown terminal. For PUTCSR and GETCSR, BBCDIST.MAC is using some unknown control sequence, while patch.z80 is writing directly to the I/O ports for some unknown CRT controller chip.

Having a separate patch file isn't really that useful anyway now that the code is open source, so in my fork, I have removed the patch file and moved the functions it contained elsewhere.

I renamed cmos.z80 to cpm.asm and moved the BYE and INKEY routines from patch.z80 there, along with the table defining the control keys. Now all of the functions that use BDOS and/or implement * commands are consolidated in this file. The OSLINE function that uses the control key definition table is also located there.

I renamed sorry.z80 file to hardware.asm and moved the GETTIME, PUTTIME, CLRSCN, PUTCSR, and GETCSR routines there. I have rewritten them to send ANSI escape sequences to clear the screen and position the cursor. I also implemented the COLOUR function using ANSI escape sequences.

I am now working on writing the unimplemented graphics routines for the TMS9918A video chip. So far, I have working MODE, GCOL, and PLOT routines. PLOT is only partially implemented and can only plot individual pixels currently rather than lines and other shapes. My version of BBC BASIC will still work without a TMS9918A; if it's not there, the routines just don't do anything. It would also eventually be possible to make them conditionally compile so they don't use memory if they're not wanted.

Those should be fixed. Thanks very much.

I do need to produce versions of Basic specialised for cpmish's various terminals --- easy, since there's only one so far (an ADM-3A/Kaypro II hybrid). This will involve a bit of rearrangement such that each terminal gets its own assembler file, and then you just link things correctly.

Regarding the graphics routines: that's outside my scope, happily. The BBC MOS graphics routines were incredibly carefully written (the Master ones even more so).

Do you know if there's a GSX extension for the TMS9918A? If so, you may be able to steal bits from there...

I am not aware of a port of GSX to TMS9918A. I actually plan to use the bitmap graphics routines from R.T. Russell's patch for the Z88: http://www.rtrussell.co.uk/bbcbasic/Z88PATCH.MAC. It looks like it will be possible to change only a few functions, namely UPDATE, which sends data to the screen and LOCATE, which calculates the address of the byte containing an X,Y coordinate on a screen. Although the specifics of which byte contains which coordinate are different, fundamentally, the TMS9918 stores 8 pixels to a byte, the same as the Z88, so the line drawing and flood fill routines should work. Of course the TMS9918 also supports color, but the foreground and background color for each group of 8 pixels is stored in a different area of memory so I can handle that separately.

I didn't know that existed --- it's a really useful source for optimised graphics routines. However, I don't see GCOL, so I'd guess you'd have to use PLOT to draw in the background colour to erase. It'd be easy to implement. Windowing, likewise.

Thinking of cpmish, one thing I've been wondering about is a generic graphics interface; something as simple as possible which the BIOS could expose which could be used by application programs (possibly via GSX) to draw on the screen. But, video memory is nearly always not visible to the CP/M application. The most flexible would be a call which copies a window from a shadow framebuffer onto the physical screen, similar to UPDATE here (plus another call which describes the screen size). It wouldn't be particularly quick but it would do business graphics fine. This could would need very little modification to work on that.

A graphics interface is a good idea. I am not sure about GSX specifically though since it barely saw any uptake, so no existing software would be able to use it.

A better way might be able to implement a VDU interface like the BBC micro had. The VDU basically presented as a graphical terminal where both text and graphics functions could be called via control codes. This would allow graphics to be used from existing programming languages just by using the built-in character I/O facilities.

This VDU functions could be implemented as a hook in the CP/M BIOS's CONOUT routine or even externally from the Z80. I have another project z80ctrl, which is a bootloader, debugger, and IO card for the RC2014. I've started implementing a terminal emulator using the TMS9918 here and I think I will add VDU commands to this.

I am also going to shift gears on my BBC BASIC work and just have the graphics commands send the proper VDU characters that either a CP/M BIOS or my terminal emulator can catch.

Oh, and regarding GCOL, for the TMS9918 this is just another poke to a different area in memory. I have already handled this in my current implementation of PLOT. Whenever I plot a pixel, I set the corresponding color table for the 8 surrounding pixels to the current GCOL value. There is attribute clash because the smallest area that can have a unique foreground and background color is a row of 8 pixels, but that's just a fact of life with this chip.

To remove graphics, PLOT has different arguments governing the kind of operation to do on the pixels. It will either set, clear or invert the bits being drawn to, depending on the value passed in for the first parameter.

All this still applies now that I'm planning to do graphics via VDU emulator; it's just abstracted a layer.

I'd like to avoid having the graphics part of the VDU layer baked into the BIOS, though. For platforms where we can put all the BIOS logic outside the main address space, like the NC200, it's fine... but for those platforms where all the BIOS code needs to live in main memory, every byte of unused code is a waste, and graphical VDU drivers tend to be big.

One option is to have some simple BIOS routines --- I think I need three calls: one to enter graphics mode and return screen info, one to blit a rectangle from user memory onto the screen, and a call to leave graphics mode. The VDU driver would be a seperate module, and could either be included in the BIOS if there's room or loaded dynamically: which would need me to come up with a way of doing something RSX-like for CP/M 2.2 (which doesn't really support RSXs).

It does look like a subset of the BBC VDU sequences are a good choice (well, the only choice, really); but it is worth noting that many programs, including ZCPR, assume that CONOUT drops the top bit of output bytes.

Well, for now, I've decided to do a VDU and ANSI terminal emulation on my z80ctrl board, so there's no code taking up space on the Z80. The software on the Z80 just thinks it's talking to a serial port, and the AVR translates the commands it receives to memory operations on the TMS9918A. It can also do graphics calculations a lot faster since it's got hardware multiply and a lot more IPC. I realize this doesn't help people who want to run on original hardware and I'm sure some purists would consider this cheating, but for me having a modern twist on an 8 bit computer and blurring the lines between real hardware and emulation is a lot of fun. I'm pretty much finished with the text mode terminal emulation stuff at this point, and about to start on graphics.