[question] Inline Assembly possible for the msdos86 an pc86 Targets? How?
Closed this issue · 11 comments
I would like to implement non-waiting keyboard input and some simple vga output on the msdos86 and pc86 targets.
I am grepping the repo searching for "asm" but I have not found any example.
How can I use Assembly with C? Which syntax can I use?
I need to do simple things such as:
mov ax, 0013h
int 10h
It does have inline assembly --- the em architecture doesn't allow it. Instead you have to create .s assembly files, assemble them to .o files, and link them. The ack front-end knows about assembly files so you can just add them to your source file list. The assembler syntax is kinda weird, though. See https://github.com/davidgiven/ack/blob/default/plat/pc86/libsys/_sys_rawread.s for an example. Note that you must have that section declaration clause at the top, or it won't work.
I have tried something the following code below. I see a black screen on dosbox which may be a good sign for the Assembly part but I am not sure I am able to write into the screen memory:
#define POKE(addr,val) (*(unsigned char*) (addr) = (val))
#define POKEW(addr,val) (*(unsigned int*) (addr) = (val))
#define SCREEN_BASE 0xA0000000
#include <stdlib.h>
extern void init_vga(void);
void _XL_INIT_GRAPHICS(void) {
uint16_t i;
init_vga();
for(i=0;i<1000;++i) {
POKEW(SCREEN_BASE+i,0xFFFF);
}
while(1){};
}
which I link with init_vga.s
:
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
.define _init_vga
_init_vga:
mov ax, 0x0013
int 0x10
ret
You haven't set the segment when writing --- you'll have to move POKEW into another assembly function and write it via mov [es:dx], ax
or something similar. (Remember the ack makes small mode binaries. Pointers are 16 bits.)
@davidgiven can't I just do it with the C macro POKEW that uses C pointers to write into memory?
#define POKEW(addr,val) (*(unsigned int*) (addr) = (val))
or maybe
#define POKEW(addr,val) (*(unsigned uint16_t*) (addr) = (val))
No, that just does a normal write to the 64kB data segment --- mov [ds:dx], ax
. Video memory's somewhere else entirely. Segmented architectures are fun.
Thanks @davidgiven!
So I need to implement an Assembly version of the POKEW, which takes arguments.
Do I need to do this in a different file? I don't understand the purpose of the segment declarations.
Do I need a special one for POKEW?
You can put it in the same file. The final .text
segment declaration just tells the assembler that this is code. (The initial ones make sure the segments are numbered correctly.)
The ACK passes all parameters on the stack, which is irritating. Look at https://github.com/davidgiven/ack/blob/default/plat/pc86/libsys/_sys_rawwrite.s for this.
So, there is no syntax for arguments?
I will need to have a C function that writes into screen ram: some sort of POKEW(uint16_t address, uint16_t value).
So I have two 16-bit arguments.
How can I do this? Are arguments somehow mapped to 16-bit words on the stack?
Like the first 16-bit word popped from the stack is the first argument and the second 16-bit word is the second parameter?
They're pushed onto the stack from left-to-right, and will appear above the return address. So, the last parameter is at 2(sp), the second last at 4(sp), etc. Once you've pushed the old bp they'll be at 4(bp) and 6(bp). You can see the routine I linked to above accessing a parameter at 4(bp).
Thanks! I am getting some help on how to write the routine. I don't know, yet, if I will manage. I would close this issue for the moment. I might come back with more questions if I am stuck, again.
Hello @Fabrizio-Caruso,
In case you are (still) interested in this issue:
My libi86
library, which supports ACK's msdos86
target, currently includes implementations of peek
, peekb
, poke
, and pokeb
functions for working with far addresses.
You can consider either using this through the library (in _BORLANDC_SOURCE
mode). Alternatively, you might want to study the source code to see how to implement similar functionality in your own program.
Thank you!