• Please review our updated Terms and Rules here

Writing Assemblers... What should a good assembler do?

@Laci53 The list isn't insignificant to me; but it does seem that CP/M computers other than extremely modern (post-2010) designs are insignificant to you.
 
@cjs:
Well, you see, I prefer to deliver only tested software. Bad habit...
All the interfaces I wrote were tested on the real machines (not emulators/simulators).
It is relatively simple for me to buy kits for RC2014-like machines, to build the boards, to write the code and test-it on the real machine.
Unfortunately, I could not yet procure an S-100 machine with a Cromemco 256K memory board, nor a TRS-80 Model 4P.
Sorry about this. I promise to keep trying...

Ah, I forgot an important thing.
My software is published including all the source files.
It is easy for everyone to change the code related to RAM bank switching, it is placed in a single file, well commented.
If needed, I can help.
I consider this "customization" quite simple.
Of course, there are other pieces of my software where I do not recommend such an approach (e.g my real-time multitasking operating system RTM/Z80, here: https://github.com/Laci1953/RTM-Z80 ), but in this particular case of RAM banks switching, it's easy.

regards,
Ladislau
 
I consider this "customization" quite simple.
...in this particular case of RAM banks switching, it's easy.
Ok. So explain how you would customise the code for the Cromemco bank switching scheme. (And feel free to include a link to the current code.)

IIRC, setting any of bits 0-6 at port $40 makes the system read from and write to that bank at all addresses $0000-$FFFF. Setting bit 7 causes writes to be written to all banks. (Reads are still from the one selected bank.) There's more here.
 
Last edited:
As for this:
Unfortunately, I could not yet procure an S-100 machine with a Cromemco 256K memory board, nor a TRS-80 Model 4P.
Read in light of this:
In my opinion, a good Z80 assembler, running on CP/M, should be also able to handle very large source files.
Therefore, I modified ZAS in order to use (for computers provided with 128/512KB RAM) the "extra" RAM, and succeeded.
It seems that by your own definitions, your modified ZAS is not a "good Z80 assembler" on S-100 machines using memory boards from the company that pioneered bank switching on S-100, and also not a "good Z80 assembler" on one of the most popular >64K machines that could run CP/M. Your words, not mine.
 
I understand that CROMEMCO uses 4 x 64KB RAM banks.

The big problem here is to have a small "free" space, in the BIOS range of addresses, where a small "shared code" must be stored.
For example, in the case of RC2014's SC108, I used the area 0FF63H to 0FFFFH.
There, at the start of the program who wants to use "extra" RAM, a routine will store a set of small routines (GetByte, PutByte, etc) that will move bytes between the RAM banks.

(Small story: in the RC2014 case, I was constrained to modify the BIOS in order to "obtain" this little "free" area)

Ok, in the hope that the previous step succeeds, let's take, for example, the CGEN component of my enhanced HiTech C. CGEN will need only 2 x 64KB banks.
The file to be modified is https://github.com/Laci1953/HiTech-C-compiler-enhanced/blob/main/CGEN/alloccg.as

The significant setting is ?2X64K (must be set to 1 : ?2X64K equ 1), all the rest must be set to 0 (?512K, ?Z80ALL, ?ROMWBW)
Then, in the second set of settings, a new CROMEMCO option must be added (CROMEMCO equ 1), all the rest must be set to 0 (SC108, MM, S80)
Then, a new section of code, starting with IF CROMEMCO and ending with ENDIF, must be added.
It will contain:

IF CROMEMCO

MACRO LOW_RAM
ld a,0
out (40H),a
ENDM

MACRO UP_RAM
ld a,1
out (40H),a
ENDM

MACRO WRITE_ALL
ld a,80H
out (40H),a
ENDM

ENDIF

Here, the _InitDynM routine must be included unchanged, but the StoreShared routine must be changed.
It will contain the code that moves code (from SHARED_START to SHARED_END) to that "high free area in BIOS" (0FF63H to 0FFFFH.)
Basically, it will contain something like:

StoreShared:
WRITE_ALL
ld de,0FF63H ;to
ld hl,SHARED_START ;from
ld bc,SHARED_END - SHARED_START ;size
ldir ;move
LOW_RAM
ret

(the routines moved to the "high free area in BIOS" are relocatable, no worry...)

(the StoreShared routine for SC108 is much more complicated, because of a 32KB ROM containing a small routine to move a byte from the first bank to the second bank)

All the rest of code:
_myalloc
_GetByte
_PutByte
_GetWord
_PutWord
_ReadMem
_WriteMem
_PutString
_GetString
_StringLen
, as they are included between IF ?2X64K and ENDIF, are valid as the are, without any change.

The modified alloccg.as must be compiled with my Z80AS ( here: https://github.com/Laci1953/Z80AS ),
then all the rest of the C source files compiled with the classic HiTech C compiler.
Use makecgen.sub and linkcgen.sub to build the new CGEN for CROMEMCO.

Let me know if you have any questions.

Ladislau

NB. In case of other hardware with 16KB RAM banks, the change is much more simpler (only MACRO SELECT & DEFAULT must be changed...)
The case of 64KB banks is the most difficult.
 
Yes CP/M was ported to Z80, for the BIOS + BDOS + CCP, and released as Personal CP/M 8 bit version 1 (AKA CP/M 2.8) in 1984 after CP/M+. The utilities were written in C, PL/M 8080ASM (PCPM.SYS[BIOS/BDOS/CCP in Z80 ASM].

Is there a copy of the original z80 code for this anywhere? It has me very curious as to what they did -

I know it's possible to convert 8080 code to z80 mnemonics ( I did that a few times and I know others did also for CP/M ) but it would be interesting to see an original source for CP/M in z80.
 
Yes
Is there a copy of the original z80 code for this anywhere? It has me very curious as to what they did -

I know it's possible to convert 8080 code to z80 mnemonics ( I did that a few times and I know others did also for CP/M ) but it would be interesting to see an original source for CP/M in z80.

Yes the sources can be found on Gaby's site.
 
Yes


Yes the sources can be found on Gaby's site.

I've gone looking for them here: http://www.gaby.de/edownl.htm

but I can't find them - Could I trouble you to point them out to me?

I wrote previously a complete replacement OS that is compatible with CP/M entirely in z80, so finding other examples of z80 native code for CP/M ( as opposed to 8080 translated into z80 ) is of great personal interest to me.

Thanks
David
 
IMSAI also had their own bank switched S-100 memory, their ad took up the back cover of (IIRC?) BYTE or was it Kilobaud back in the day.
The ad doesn't mention CP/M at all. Also loved the comment "I could change my high school grades with that thing" LOL

I did change my high school grades back in the day, on a Microbee by using the disk hex editor.

The school foresaw that someone might try that, so they copied the grades to every single system disk in the lab. About 20 of them. Pretty foresightful.

Unfortunately, they didn't foresee me showing everyone else in the class how to do it, and pretty soon 20 terminals were all being used to change everyone's grade, so 20 copies of the grades all got corrupted in the same session. We thought it was great fun, and that the grades were just exercise data, because honestly, it wasn't that difficult to find and change - no one knew they were real until the teacher came back in and saw someone doing it and told them to stop, then realized the same thing was happening on every workstation and quickly worked out that this wasn't just one corrupted disk any longer... Fortunately, because it was so widespread, no one got into any trouble, but yeah, we completely damaged the data so badly they never managed to recover it. I don't know what they did to try and fix it after that.

Sure enough, all the fingers got pointed at me when he asked who showed them though, and I did fail computing as a result.
 
I've gone looking for them here: http://www.gaby.de/edownl.htm

but I can't find them - Could I trouble you to point them out to me?

I wrote previously a complete replacement OS that is compatible with CP/M entirely in z80, so finding other examples of z80 native code for CP/M ( as opposed to 8080 translated into z80 ) is of great personal interest to me.

Thanks
David

unofficial cpm
dri sources
personal cpm (not personal cpm-86)


Tom
KE6JAG
 
IF CROMEMCO

I like this approach - I assume the inclusion of the extra memory support that is machine specific is user-configurable from the source on recompilation :) So compatability with unexpanded machines ( or with incompatible memory expansions ) is achieved through this method?
 
@cjs :

I attached the CROMEMCO customized version of alloccg.as

Assembling with Z80AS - passed. Tell me if you have any questions.

On the issue of customizing the BIOS:

I did it studying the BIOS code and changing little pieces of code that clearly were a heritage of the old 8080 code.
The BIOS used in RC2014 is the old Grant Searle BIOS, with some adjustments (e.g. CF related code, instead of floppy)

Example:

Old code:

match:
;copy data to or from buffer
ld a,(seksec) ;mask buffer number
and secmsk ;least signif bits
ld l,a ;ready to shift
ld h,0 ;double count
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
; hl has relative host buffer address
ld de,hstbuf
add hl,de ;hl = host address
ld de,(dmaAddr) ;get/put CP/M data
ld bc,128 ;length of move
ld a,(readop) ;which way?
or a
jr nz,rwmove ;skip if read
;
; write operation, mark and switch direction
ld a,1
ld (hstwrt),a ;hstwrt = 1
ex de,hl ;source/dest swap
;
rwmove:
;BC initially 128, DE is dest, HL is source
ldir
; data has been moved to/from host buffer
ld a,(wrtype) ;write type
cp wrdir ;to directory?
ld a,(erflag) ;in case of errors
ret nz ;no further processing
;
; clear host buffer for directory write
or a ;errors?
ret nz ;skip if so
xor a ;0 to accum
ld (hstwrt),a ;buffer written
call writehst
ld a,(erflag)
ret

Changed code:

match:
;copy data to or from buffer
ld a,(seksec) ;mask buffer number
and secmsk ;least signif bits
;
; ld l,a ;ready to shift
; ld h,0 ;double count
; add hl,hl
; add hl,hl
; add hl,hl
; add hl,hl
; add hl,hl
; add hl,hl
; add hl,hl
;
ld h,a
ld l,0
srl h
rr l ;HL = L << 7
;
; hl has relative host buffer address
ld de,hstbuf
add hl,de ;hl = host address
ld de,(dmaAddr) ;get/put CP/M data
ld bc,128 ;length of move
ld a,(readop) ;which way?
or a
jr nz,rwmove ;skip if read
;
; write operation, mark and switch direction
ld a,1
ld (hstwrt),a ;hstwrt = 1
ex de,hl ;source/dest swap
;
rwmove:
;BC initially 128, DE is dest, HL is source
ldir
; data has been moved to/from host buffer
ld a,(wrtype) ;write type
cp wrdir ;to directory?
ld a,(erflag) ;in case of errors
ret nz ;no further processing
;
; clear host buffer for directory write
or a ;errors?
ret nz ;skip if so
xor a ;0 to accum
ld (hstwrt),a ;buffer written
call writehst
ld a,(erflag)
ret

Another example:

Old code: (when reading from CF)

LD c,4
LD HL,hstbuf
rd4secs:
LD b,128
rdByte:
in A,(CF_DATA)
LD (HL),A
iNC HL
dec b
JR NZ, rdByte
dec c
JR NZ,rd4secs

Changed code:

; LD c,4
; LD HL,hstbuf
;rd4secs:
; LD b,128
;rdByte:
; in A,(CF_DATA)
; LD (HL),A
; iNC HL
; dec b
; JR NZ, rdByte
; dec c
; JR NZ,rd4secs

ld hl,hstbuf
ld bc,CF_DATA
inir
inir

This way, not only the code size decreases, but also the execution speed increases !

Any questions on this topic?

By the way, I suggest, in order to not interfere with this conversation related to assemblers, to create a new thread, about the topic you are interested in.

agreed, cjs ?

thanks,
Ladislau
 

Attachments

Example: ...
That code you posted is unreadable to due to being reformatted as natural-language text. Try putting it in a code block. (If you can't edit that post, the edit window has expired and you'll need to make a new post.)
 
@cjs :
You wrote: "It seems that by your own definitions, your modified ZAS is not a "good Z80 assembler" on S-100 machines using memory boards from the company that pioneered bank switching on S-100, and also not a "good Z80 assembler" on one of the most popular >64K machines that could run CP/M. Your words, not mine."

I do not understand what do you mean.

My modified ZAS works on all sorts of expanded memory ( N x 64KB, N x 32KB, N x 16KB ).
In other works, it can cope with 64KB banks, 32KB banks, 16KB banks.

But, keep in mind, this customized ZAS was designed to be used ONLY with the enhanced HiTech C compiler. It does not provide support for macros, includes, conditionals. But, on the other hand, it does assemble huge source files (25000 lines, 1300 symbols).

If you need to assemble source files using macros, includes, conditionals, undocumented Z80 ops, Z80AS is the answer. It can cope with large source files too (e.g. BDOS + BIOS as a single file).

thanks,
Ladislau
 
That code you posted is unreadable to due to being reformatted as natural-language text. Try putting it in a code block. (If you can't edit that post, the edit window has expired and you'll need to make a new post.)


He means click on the vertical ... hamburger and then on the >_ and then select inline code while highlighting the code.

Capture.JPGIt makes the code look like this;

; LD c,4
; LD HL,hstbuf
;rd4secs:
; LD b,128
;rdByte:
; in A,(CF_DATA)
; LD (HL),A
; iNC HL
; dec b
; JR NZ, rdByte
; dec c
; JR NZ,rd4secs


You should be able to go back and edit the post and make it like that - :)

It just makes it look nicer and is a little more readable. (edited, my addition was confusing... I responded to the wrong post)
 
Last edited:
Back
Top