Bare metal programming

Bare metal programming means coding your own operating system, or just whatever software that boots itself. I want to make a couple of simple games, such as Pong, Tetris, Breakout... those are easy, but I'm coding everything in assembly (it is possible to link C code, but I decided to do everything in asm as a exercise). Here's what I have so far. This is a fake loader screen that is supposed to mimic loading and depacking some software on C64. This code could actually be much simpler. The text rendering code works with real C64 fonts, I could have just draw it like a normal image. I also wrote a keyboard handler, so I can write to the screen, but this will be cut, since the "loading" is automated. I will release the source once I finish the whole thing. This is supposed to be one of demos for my resume (I don't have any computer science education or real experience).

If you want to learn bare metal coding, visit wiki.osdev.org/ and their forum. It's great !

Other urls found in this thread:

www1.zippyshare.com/v/DRaeRGJB/file.html
twimgs.com/ddj/abrashblackbook/gpbb47.pdf
twimgs.com/ddj/abrashblackbook/gpbb48.pdf
pouet.net/prod.php?which=50141
ctyme.com/intr/rb-0273.htm
ctyme.com/intr/rb-0274.htm
gnu.org/software/grub/manual/html_node/videoinfo.html#videoinfo
chrysocome.net/rawwrite
spike.scu.edu.au/~barry/interrupts.html#ah3f
unixwiz.net/techtips/x86-jumps.html
twitter.com/SFWRedditGifs

This reminds me of how happy I am that I'll never have to do this again.

Maybe it's because I'm too young and I missed on such low level coding, but I really like it a lot. I guess you could tell by looking at the thing I did, I really love the C64.

You should make a baremetal C64 emulator, Assembly is awesome, if you need any help make sure to post, not enough people know assembly and we can all share weird tricks!

Isn't talking about Assembly like talking about generic Lisp, and thus meaning literally nothing but a family of languages?

I was mostly kidding. Low level programming can be incredibly fun and rewarding. But it can also get very frustrating, very fast if it is something you have to do, rather than something you want to do.

The big problem of bare metal coding is that you can't get a VSYNC on all hardware. the VGA has a vsync bit that you should poll to know when you're in sync, but it's not emulated on new hardware. I have a Pentium 1 laptop and it works on it (as well as other VGA functions such as changing the standard colors in the palette), I'm trying to do my thing in such a way, that it will work on all hardware, or at least the majority.
Also there's a problem of sound. There's no point in doing C64 emulation without the epic sid chip, but with bare metal you can only get the PC speaker, unless you want to write a driver for every sound card there is ! Although I'll consider writing a driver for AdLib / Sound Blaster.
And a final reason I don't want to do it. C64 is not trivial to emulate, it's not NES, where 99% of software uses only the official features. C64 coding is full of weird bugs and fucking around with video timings.

here's download to that thing you can see in the OP. You can boot it from virtual box and probably any other VM software (I didn't test anything besides virtual box). It is a floppy image.

Download it : www1.zippyshare.com/v/DRaeRGJB/file.html


I get you man. I'm only 22 yo and I've found out about C64 and Amiga only 2 or 3 years ago. They are such a great machines. I own a A500 now, got it for really cheap !

Wew. Good fucking luck screwing around with different BIOSes/BIOS vendors and hardware setups.
I mean, I love bare metal programming as well, but if you're looking into making it run everywhere, I'd strongly consider programming for emulators (such as DOS, or any game console emulators) instead.

The thing I have now should work on everything that supports the BIOS boot from floppy. I internationally only use the features that are supported for sure.
Different id cuz posting from phone

lol! Welcome to the world of bare metal. You'll join my laughter when you've run out of curses.

very yes

we'll see. I'm really not doing anything advanced here.

I thought TempleOS was bare metal 4 everyone on amd64?

I only now realized, that this board doesn't have IDs lol.

Just to add a bit more, I'm not using any BIOS functions except for loading from floppy and going into [email protected]/* */ graphics mode. Then I go into protected mode and all my code is 32bit. I'm using PIT to generate interrupt at ~1000Hz to have a timer and a keyboard interrupt. I don't see how could this break, those are all essentials. But we'll see, I wouldn't be surpriced if there would be some discrepancies... I also need to make it bootable from CD. I think that's the safeset way of booting on a modern PC. I don't want to use GRUB or any other loader lile that, because those load an ELF straight into the protected mode. This is just a stupid idea I've got few days ago. I'm collecting all my past projects, so I can show it on my resume. The best thing I've done (although i was lile 15-17 when I coded it, so it's not vety pretty) was a dynamic library for a certain mmo server side executable fixing a lot of bugs and adding new features. Said server was runnimg on BSD, so I had to learn some basics of *nix, that also helped me a lot with abandoning windows and going GNU/Linux

I think this is my first time I called it GNU/Linux

templeOS itself is a bare metal software, lile any other OS (or the kernel at least). If you code for the TempleOS I'd argue that it's not bare metal anymore, but still very close

so thats what wizards do after they completely give up on life?, sounds neat

I'm on a chan, whadda you expect ?

This sort of shit earned me my first house.

Well as I said, this is a small project to boost my resume. I need some actual working stuff, since I didn't finish any computer school. The library that I mentioned before... I don't know if I want to show that on my CV. The private servers for this MMO are illegal and people are making tons of money on them (including me couple of years ago) so idk if I want to admit to doing that. At the same time, it's quite big and it does a lot of cool stuff and I'm proud of it.

I also made several cheats for that game, do you think I should show it ? Here's a random snippet of one of them
extern "C" void __declspec( naked ) CreateInstanceHook_asm(){ __asm { pushad push esi call CreateInstanceHook_c add esp, 4 test eax, eax jz DontRenderLabel popad mov eax, [esi + 20] push edi push eax push 0x0042B32B ret // if the code jumps to this address // it will render the actor he found. // the jump below (0x0042B351 skips the rendering) // so the map will look empty, even though client // has received the packet about all the actors. // the function above (CreateInstanceHook_c) can // put these actors to some array if needed.DontRenderLabel: popad xor eax, eax push 0x0042B354 ret }}extern "C" void __declspec( naked ) OnSelectPhase(){ __asm { mov gSelectPhase, 1 push 0x5B71B0 push 0x420F68 ret }}extern "C" void __declspec( naked ) ONGamePhase(){ __asm { mov gGamePhase, 1 mov gSelectPhase, 0 push 0x5B6B38 push 0x0041D139 ret }}extern "C" void __declspec( naked ) ONLeaveGamePhase(){ __asm { mov gGamePhase, 0 mov first_vid, 0 mov byte ptr [esi + 0x7B3D],0 push 0x00418006 ret }}extern "C" void __declspec( naked ) SetPixelPosition(DWORD* pos){ /* SetPixelPosition will put your character (or any actor, but this funcion has a fixed pointer to main character) on a certain coordinants on the map. It's basically a teleporter funtion, the problem is, though, that the server checks if the character moves to fast, so you can only jump by 20k units before the server will send you back (and leave some log about the hack for sure). It can be countered very easely, all you have to do is loop the SetPixelPosition with 10/20k jump in a loop with 10-50 ms cooldown. That basically makes a "slow" teleporter (which is still faster than normal walking of course) */ __asm { push ebp mov ebp, esp push ebx push ecx // push ecx to preserve it sub esp, 20 mov ebx, [ebp + 8] push ebx mov ecx, dword ptr [0x619980] mov ecx, [ecx + 16] mov eax, 0x0040C680 call eax add esp, 20 pop ecx pop ebx pop ebp ret // now we should have our character's instance in ecx // and the call bellow takes it as an argument through ecx }}void Teleport(float x, float y){ //float poss[3] = {x,y,0}; //SetPixelPosition((DWORD)poss); DWORD PythonPlayerInstance = *(DWORD*)(0x61997C); ((void(__fastcall*)(DWORD,DWORD,bool,bool,bool,bool))0x0043DA40)(PythonPlayerInstance,0,0,0,0,0); DWORD Base = *(DWORD*)(*(DWORD*)(0x619980) +16) + 476; float pos[3] = {x,-y,0}; ((void(__fastcall*)(DWORD,DWORD,float*))0x4A3E10)(Base, 0,pos); ((void(__fastcall*)(DWORD,DWORD,bool,bool,bool,bool))0x0043DA40)(PythonPlayerInstance,0,1,0,0,0);}

Show off the stuff you are proud of on its own (if possible) and then mention that "some people" successfully used it to create a server emulator for X MMO, in a footnote. No need to mention that it was unauthorized or illegal.

I had 3 servers, then I've quit the "scene" because it was full of stealing faggots, they'd say stuff like "lol, the private servers are illegal anyway, so you can't do shit" while depacking your client and taking your custom models or maps. That's why I decided to do everything server side (I had no problems with people cloning my stuff on their own). After that I had one or two guys who would buy some features and fixes from me, so I guess that was legal, right ?

Here's some piece of that code
#include "pets.h"/*Function for naming your pet. There was something wrong in the originalfunction, I copy pasted the dissasembly and fixed it. I don't remember anymorewhat exactly was wrong there. This function is called from a quest (look quests.cpp)*/void pet_name_asm(SCHAR* pet, char* name, int len){ asm(".intel_syntax noprefix\n" "push edi\n" "push esi\n" "push ebx\n" "sub esp, 40\n" "mov eax, [ebp+8]\n" "test eax, eax\n" "jnz pet_detected\n" "jmp end_of_name_asm\n" "pet_detected:\n" "add eax, 260\n" "mov [esp], eax\n" "mov ebx, [ebp+12]\n" "mov [esp+4], ebx\n" "mov ebx, [ebp+16]\n" "mov [esp+8], ebx\n" "mov eax, 0x804D16C\n" "call eax\n" "jmp end_of_name_asm\n" "end_of_name_asm:\n" "add esp, 40\n" "pop ebx\n" "pop esi\n" "pop edi\n" "pop ebp\n" "ret\n" );}bool raceisPet(int race){ if (race >= 34001 && race GetRaceNum(); if (!raceisPet(id)) { return id; } return 0;}extern "C" void PetID_hook_asm(void){ asm(".intel_syntax noprefix\n" ".globl PetID_hook_c\n" "add esp, 4\n" "call PetID_hook_c\n" "test eax, eax\n" "jz is_pet\n" "push 0x0807D00D\n" "ret\n" "is_pet:\n" "push 0x807D056\n" "ret\n" );}/*Admins have a command /purge which deletes all monsters and NPCs in certainradius. We need to hook this function and clear few things. I also addeda chat messagge letting you know why did you PET dissapear */extern "C" void Purge_hook_c(SCHAR_MANAGER* CM, SCHAR* a1){ int num = a1->GetRaceNum(); if (raceisPet(num)) { a1->rider->pet = 0; SCHAR* pc = a1->rider; a1->rider = 0; pc->SetQuestFlag("pet.is_summon", 0); a1->ChatPacket(1, locale_find("pedisga")); //Your pet has vanished, probably because of GM } CM->DestroyCharacter(a1);}extern "C" void purge_hook_asm(void){ asm(".intel_syntax noprefix\n" ".globl Purge_hook_c\n" "add esp, 4\n" "call Purge_hook_c\n" "push 0x080D1AF2\n" "ret\n" );}/*This function is just sort of a safety net. Could be skippedIt looks for a list of all characters on the server and checksif it really exist. Prevents deleting bad pointers*/void DestroyIfExist(SCHAR* a1){ SCHAR_MANAGER* CM = SCHAR_MANAGER_SINGLETON; if (CM->Find(a1->vid)) { CM->DestroyCharacter(a1); }}/*The exp system... if your PET is close enough to you and you haveenabled exp sharing, every piece of experience you get from killed monsterswill be split between you and your PET. Pets with higher level have strongermagic skills (the skills code is in character_hooks.cpp) */extern "C" int pet_exp_system_c(SCHAR * player, SCHAR * mob, int exp) // 08086D5E 8nop{ if (player->pet && player->pet->level < 20 && player->b_petexp && distance(player, player->pet) CreateFly(1, player->pet); int exp_p = player->GetQuestFlag(qfname)+exp/10*player->b_petexp; player->SetQuestFlag(qfname, exp_p); CHARACTER_ChatPacket(player, 5, "pet_e %d", exp_p); if (player->GetQuestFlag(qfname) >= pet_exp_table[player->pet->level-1]) { player->SetQuestFlag(qfname, 0); player->pet->level++; player->SetQuestFlag(qfname2, player->pet->level); player->ChatPacket(1, locale_find("pelvup"), player->pet->level); //Your pet has level'd up ! (lv %d) player->ChatPacket(5, "pet_l %d", player->pet->level); } return exp/10*(10-player->b_petexp); } return exp;}extern "C" void pet_exp_system_asm(){ asm(".intel_syntax noprefix\n" ".global pet_exp_system_c\n" "add esp, 4\n" "push eax\n" "mov eax, [ebp-0x30]\n" "push eax\n" "push edi\n" "call pet_exp_system_c\n" "add esp, 12\n" "mov dword ptr [esp+0x10], 0\n" "mov ebx, 0x08086D66\n" "jmp ebx\n" );}void HOOK__PETS(int offset){ CallPatch((int)&purge_hook_asm+3, IPS(offset+0x080D1AED), 0); CallPatch((int)&PetID_hook_asm+3, IPS(offset+0x0807D008), 0); CallPatch((int)&pet_exp_system_asm+3, IPS(offset+0x08086D5E), 3);}

This was coded around 2012-2014 and I added English comments few weeks ago.

green text?

bump

...

how do i make games in asm?

Depends what kind of game you want to make.
But first thing is to learn to write basic assembly programs.

really cool work, good job.

I miss the A500 days. I wish PC hardware was more standardized, or more open & better documented at the hardware and firmware level. I did some stuff with Borland Assembler many many years ago but it just wasn't the same as messing around with the A500.

I second this, I'd like to see a greentext

Same way as in any other language.

Yeah yeah, right. Maybe next time, maybe not. If I wanted to seriously sink some time in such a project I'd just try coding on C64 or Amiga.
Yeah, because my 64kb or less piece of code really needs a 64bit cpu... This shit will fly on 486

I know you're just meming, but I wanted to make it clear.
I didn't post any progress, I had some problems, especially with the emulation. Going every few minutes with a new build to a real HW is tiring... but what can you do.

The point is that long mode is much easier and nicer to program. Though of course if you really want to see it run on that vintage toaster, I don't blame you.
Why don't you test it first in a VM then?

Also, mode-x kicks VGA ass. You should try it once.
twimgs.com/ddj/abrashblackbook/gpbb47.pdf
twimgs.com/ddj/abrashblackbook/gpbb48.pdf

I'm not memeing user, I'm dead serious.

I do that, but VM doesn't emulate everything in real time. For example, I programmed the PIT to generate interrupt at 1000 HZ and I use it to count miliseconds. Most of the time VMs do it right, but sometimes it slows down a lot. Same with other such functions. I'm a the point where I am doing a lot of drawing on the screen and it's fucking slow. It might be just my host PC that is slow but god damn... ~2Ghz i3 with light linux should do the job just fine.

I know about the mode-X and it's cool and all, but it would be an overkill for the thing I am working on.

Just to add a bit more. All of this x-mode coding wont work on the modern system, because modern GPUs emulate the VGA just barely, so you can get that minimum display going. For example, on my modern PC I can't even change the standard palette or get a VSYNC, so I don't expect anything more complex like mode-X to work on it. I want a solution as universal as possible and using the BIOS functions to get a screen mode seems like exactly that. Then I go to protected mode and just manipulate the pixels by writing to the memory. There's no way I can think of this could not work...

AVR demos is where it's at now, tbh fam.
pouet.net/prod.php?which=50141

I know LFT and this demo. He made one more demo on this board where he generates a PAL signal. And his latest C64 demo is really hot stuff too. I especially like the double wide screen AGSP and the extreme sprite crunch allowing him to display 8 sprites per line pretty much on every line.

After almost 3 weeks of lazyness (beating gta sa 100% is a serious business) and I have to give it back to

Because my shit didn't fly to good on my old P1 laptop. The "C64 loader" works fine, but then it crashes and just reboots, while it works on my modern computer and on emulators. Maybe it's just a bad floppy I have, but I'm reading the image I wrote to it and it seems to be identical.
That's another big problem I have. I fucking can't find a tool that will just do a raw write to a floppy, all the programs except a valid floppy image... Not even mentioning, that most of them only work on 1.44 Mb floppy, I have 720k ones (One of my amiga floppies). Coping my image to a real floppy is a big hustle. Here's the process :

1. Upload the image somewhere
2. Boot to win98 and download the file (PCMCIA WI-IF card)
3. Boot into Damn Small Linux from CD
4. After 5 minutes of booting, dd the image to a floppy
5. Reboot and try booting from a floppy

As you can imagine, testing this shit on a real HW like that is not good. I have 3 options
1. Get myself a USB-floppy drive and just dd it on my normal PC
2. Make the image bootable from CD, I'd do that already, but I need to get myself a CD-RW
3. Code my own tool for DOS/Win9x which will do a raw write to a floppy (which shouldn't be terribly hard, as most of the work is done by the BIOS)
I'm also thinking about making a program that would load my image into memory and jump there from DOS.

Video related, my thing running on a modern PC and then on the old P1 laptop. Do you have any ideas why it might be crashing ? I am doing some pixel drawings into a framebuffer at 0x20000 (which should be available memory in the 1MB low mem region) and then copy that framebuffer to a real framebuffer at 0xA0000. I even added some sleep functions in between each drawing functions (for the logo, and the text and so on) or just left one on. Sometimes it doesn't crash, but there's still garbage on the screen and it never changes. Sometimes I can see a part of a logo.

VGA/VESA BIOS functions are fucky. My guess is either the video mode isn't supported by that laptop, or something is different from that video mode that you're not taking into account. I'm not sure if you're using int10ax4f00 and int10ax4f01 to get the VESA mode info. In particular you need to take at least take the reported location of the framebuffer into account, and the amount of bits per pixel, as well as probably other things. As a minor caveat, I've had a BIOS which wouldn't give me all available video modes unless I wrote "VBE2" at ES:DI before calling int10ax4f00.
I'm not well versed with this, but I had a similar problem on a laptop that wouldn't let me modify the lower part of the screen for whatever reason. Never managed to figure that out, however.

ctyme.com/intr/rb-0273.htm
ctyme.com/intr/rb-0274.htm

As for writing the program onto a floppy, I'm not sure whether your laptop has USB ports. If it does, and you have multiple floppies, you could write FreeDOS or something to one, and write the program from the USB onto the other floppy. Or you could install FreeDOS to the hard drive.
Another idea could be trying to make a .COM version of your program, loadable by DOS. The environment would be mostly the same except for the loading address, and you can pretty much override anything DOS might have done, since it doesn't really affect you.
I don't have such an old machine, however. Most of my BIOSes have recognized USBs simply as hard drive units, and subsequently support booting from them.

Oh, as an addition to the video mode shenanigans, try loading GRUB and using it's command line. It has a command that can print the usable video modes and give details about them.
gnu.org/software/grub/manual/html_node/videoinfo.html#videoinfo

This is a plain [email protected]/* */ VGA graphics mode. That C64 loader uses that and It works. The difference is, however, that this C64 screen doesn't use double buffering. I'm just writing directly to the 0xA0000, then when it's over I write to my own framebuffer at 0x20000 and copy that when the frame is done.

chrysocome.net/rawwrite

I tried this tool and other like that, they don't work with 720k floppies.

bump

I wrote myself a very simple "loader" that will load my os image into memory and jump there from DOS, so I don't have to deal with floppies on that old laptop for now. This loader works in dosbox (although the text isn't moving, weird), but doesn't on the real thing... It's stuck at "READ THE FILE". Do you have any idea why it might be ?
.intel_syntax noprefix.code16.macro PRINT_CHAR CHR MOV AH, 0x02 MOV DL, \CHR INT 0x21.endm.macro PRINT_STRING STR MOV DX, offset \STR MOV AH, 0x09 INT 0x21.endm.macro EXIT_TO_DOS MOV AH, 0x4C INT 0x21.endm.macro FAR_MEMCPY SRC MOV CX, 38*512 MOV SI, \SRC MOV DI, 0x7C00 XOR AX, AX MOV ES, AX CLD REP MOVSB.endm .globl _start_start: MOV AH, 0x3D MOV AL, 0x00 MOV DX, offset FILE_NAME INT 0x21#; CHECK IF WE OPENED THE FILE JNC OPEN_SUCCESS #; ERROR, CANT OPEN, EXIT PROGRAM HERE PRINT_STRING FILE_OPEN_ERR EXIT_TO_DOS NOP OPEN_SUCCESS:#; SAVE THE FILE HANDLE MOV WORD PTR [0x300], AX PRINT_STRING FILE_OPEN MOV BX, WORD PTR [0x300] MOV AH, 0x3F MOV CX, 38*512 #; TODO : READ THE SIZE OF FILE, NOT HARDCODE IT MOV DX, 0x400 INT 0x21 JNC READ_SUCCESS #; ERROR, CAN'T READ, EXIT PROGRAM HERE PRINT_STRING FILE_READ_ERR EXIT_TO_DOS NOP READ_SUCCESS: PRINT_STRING FILE_READ FAR_MEMCPY 0x400 MOV AH, 0x3E MOV BX, WORD PTR [0x300] INT 0x21 JNC CLOSE_SUCCESS #; ERROR, CAN'T CLOSE FILE, EXIT PROGRAM HERE PRINT_STRING FILE_CLOSE_ERR EXIT_TO_DOS NOP CLOSE_SUCCESS: PRINT_STRING FILE_CLOSE #; NOP OUT THE FLOPPY LOADING CODE MOV DI, 0x7C1DNOP_FLOPPY_LOOP: CMP DI, 0X7C2C JE BOOT MOV BYTE PTR ES:[DI], 0x90 INC DI JMP NOP_FLOPPY_LOOP BOOT: PRINT_STRING BOOT_READY MOV AL, BYTE PTR ES:[0x7C00 + 0x1FE] PRINT_CHAR AL MOV AL, BYTE PTR ES:[0x7C00 + 0x1FF] PRINT_CHAR AL LJMP 0, 0x7C00 FILE_NAME:.asciz "os.img"FILE_OPEN:.ascii "OPENED THE FILE\n$"FILE_READ:.ascii "READ THE FILE\n$"FILE_CLOSE:.ascii "CLOSE THE FILE\n$"FILE_OPEN_ERR:.ascii "CAN'T OPEN os.img\n$"FILE_READ_ERR:.ascii "CAN'T READ FILE\n$"FILE_CLOSE_ERR:.ascii "CAN'T CLOSE FILE\n$"BOOT_READY:.ascii "LET'S GO !\n$"

this is not rust

well memed my friend
I'd also like to add that if I use this FAR_MEMCPY macro :
.macro FAR_MEMCPY2 SRC XOR CX, CX MOV ES, CX MOV DI, 0x7C00 MOV SI, \SRCLB1: CMP CX, 38*512 JE LB2 MOV AL, BYTE PTR DS:[SI] PRINT_CHAR AL MOV BYTE PTR ES:[DI], AL INC CX JMP LB1LB2:.endm

it doesn't boot even in dosbox (I wanted to make sure that these bytes get copies), what's wrong with this routine ? Should work exactly like the previous one...

Maybe check the contents of AX to see how many bytes were actually read?
spike.scu.edu.au/~barry/interrupts.html#ah3f
Also, maybe you're using the wrong opcode. CX register is not same as CF, right? You're using JNC, to check for carry flag, but the read sets CX, so you probably need JCXZ.
unixwiz.net/techtips/x86-jumps.html

AH = 3Fh - "READ" - READ FROM FILE OR DEVICE

Entry:

BX = file handle
CX = number of bytes to read
DS:DX -> buffer for data

Return:

CF clear if successful - AX = number of bytes actually read (0 if at EOF before call)
CF set on error AX = error code (05h,06h)

The real laptop seems to be stuck at MEMCPY, like there's something important at 0x7C00 and i'm overwriting it or something...

Why don't you write somewhere else then? XDDD

All other addresses are monitored by the CIA.

Do you know why the second memcpy fails ? Is that the right way to address stuff ? SegmentReg:[addr] ?

I guess that's the right syntax (Segment:Offset = Segment x 16 + Offset), but how do the SI and DI registers get incremented during that loop?

I'm a fucking idiot and missed that. Now it works like the previous macro and I can confirm, that all bytes get copied correctly, it still fails on the real laptop.. the fuck

I made a memcpy which also prints the dest address every iteration.
[code]
.macro FAR_MEMCPY SRC
MOV CX, 38*512
MOV SI, \SRC
MOV DI, 0x7C00
XOR AX, AX
MOV ES, AX
CLD
REP MOVSB
.endm
.macro FAR_MEMCPY2 SRC
XOR CX, CX
XOR AX, AX
MOV ES, AX
MOV DI, 0x7C00
MOV SI, \SRC
LB1:
CMP CX, 38*512
JE LB2
MOV AL, BYTE PTR DS:[SI]
MOV BYTE PTR ES:[DI], AL

MOV AX, DI
PRINT_BYTE AH
PRINT_BYTE AL
PRINT_CHAR '\n'
INC CX
INC SI
INC DI
JMP LB1
LB2:
.endm

PRINT_BYTE takes 8bit number and prints it on the screen, IT works fine on dosbox and I see all the correct addresses. On my real laptop... well, first of all. The text doesn't appear normal. It goes to the next line, but it's also shifted to the right like here

and the address seems to be always 0x7C37, then it goes to 0x7D37.

I think the DOS interrupt stuff needs CRLF sequence, instead of just LF or else you'll get the staggered output.
Does PRINT_BYTE modify any of the registers you want to display?
Anyway DosBox probably isn't the best environment to test in. It's really meant to be a generic "DOS environment" for games, instead of accuractly emulating any specific hardware. You might be better off using something like 8086tiny, PCem, or maybe even Bochs.

Ok thanks for the tip, I'll look into that. As you can see, normally I use QEMU when emulating a x86 booting, but my thing doesn't work right on the real old laptop, so I though of loading it from DOS to save myself the hustle of writing it to floppy.

I made some small progress today, I decided to leave the DOS problem for later (although with your clue now maybe it will work soon) So here I present you the "finished" game selection screen. I will have to change the horrid colors yet, but other than that, I think I'm done with this screen. There's more that could be done (and I've made more effects of this type before on normal OS) but I need to get into coding the god damn games already. I expect to finish at least one by tomorrow and I'm saying that here, so you can bully me if I don't !

Allright, I'm few days late, but just an hour after my last post I've found the perfect job offer (i.e very low requirements) so I spent all that time pushing my code on git and writing the resume (excuses, excuses), I'd show you, but I'm not sure if I want to expose my real name here. Anyway, here's the first prototype of pong. It's very primitive, the balls only has 4 directions it can go and there's no score displayed yet, but that's coming of course. I also tested my thing on yet another old computer (100Mhz pentium 1) and it works on it, so there's something special about my MMX laptop which crashes.... investigation is still ongoing.

Looks nice! What video mode is it running in?

Senpai plz desu.

Everything is in the standard [email protected]/* */ mode that most DOS games use. The funny thing is, that the C64 screen (without the border) is already 320x200, so by drawing those artificial borders I lower my real resolution.

Yeah say something about it, dubman

Ok, here's a question/problem to the DOS guys (yet another one). I wrote myself a small program that does a raw write to a floppy using the BIOS functions. Very simple, it should just load my image (which is less than 64kb so I don't have to play around with segments that much yet) and write it to the very begging of the floppy, which is head 0, track 0, sector 1. I'm getting an error nr 4 which is "Request sector not found". What could go wrong ?

.intel_syntax noprefix.code16.macro FAR_MEMCPY SRC, DST, SIZE, DST_SEG PUSHA MOV CX, \SIZE MOV SI, \SRC MOV DI, \DST MOV AX, \DST_SEG MOV ES, AX CLD REP MOVSB POPA.endm.globl _start_start: MOV DX, offset WELCOME_STR CALL PRINT_STRING#; READ THE ARGUMENT, WHICH WILL BE THE FILE NAME XOR BX, BX MOV BL, BYTE PTR [0x80] CMP BL, 126 JA NO_ARGUMENTS#; ADD TERMINATING 0 MOV BYTE PTR [BX + 0x81], 0 #; OPEN THE FILE MOV AH, 0x3D MOV AL, 0x00 MOV DX, 0x82 INT 0x21 JC OPEN_FILE_FAIL MOV WORD PTR [FILE_HANDLE], AX#; MOVE THE FILE POINTER TO THE END OF OPENED FILE MOV BX, WORD PTR [FILE_HANDLE] MOV AH, 0x42 MOV AL, 0x02 XOR CX, CX XOR DX, DX INT 0x21 JC OPEN_FILE_FAIL#; NOW WHE HAVE THE SIZE OF THE FILE IN DX:AX (32BIT)#; WE ONLY NEED THE AX, AS THIS PROGRAM CAN ONLY WRITE#; 64KB IMAGES (RIGHT NOW) MOV WORD PTR [FILE_SIZE], AX PUSH AX MOV DX, offset FILE_SIZE_STR CALL PRINT_STRING POP AX CALL PRINT_WORD MOV DL, '\r' CALL PRINT_CHAR MOV DL, '\n' CALL PRINT_CHAR #; NOW MOVE THE FILE POINTER BACK TO THE BEGGINING MOV AH, 0x42 XOR AL, AL XOR CX, CX XOR DX, DX INT 0x21 JC OPEN_FILE_FAIL#; LOAD THE FILE INTO MEMORY MOV BX, WORD PTR [FILE_HANDLE] MOV AH, 0x3F MOV CX, WORD PTR [FILE_SIZE] MOV DX, 0x1000 INT 0x21 JC READ_FILE_FAIL#; COPY THE READ FILE TO AN ADDRESS THAT IS#; ALLIGN TO 64KB... MOV AX, WORD PTR [FILE_SIZE] FAR_MEMCPY 0x1000, 0, AX, 0x1000#; WRITE THE READ FILE TO FLOPPY MOV AX, WORD PTR [FILE_SIZE] SHR AX, 9 MOV AH, 3 MOV CH, 0 MOV CL, 1 MOV DH, 0 MOV DL, 0 MOV BX, 0x1000 INT 0x13#; CHECK IF WE FLOPPY WRITE WAS SUCCESSFUL JC FLOPPY_WRITE_FAIL PUSH AX MOV DX, offset SECTORS_WRITEN_STR CALL PRINT_STRING POP AX CALL PRINT_BYTE#; CLOSE THE FILE#; WE DON'T HAVE TO CLOSE THE FILE,#; EXIT TO DOS WILL DO IT FOR US JMP EXIT NO_ARGUMENTS: MOV DX, offset NO_ARG_STR CALL PRINT_STRING JMP EXIT OPEN_FILE_FAIL: MOVZX BX, BYTE PTR [0x80] MOV BYTE PTR [BX + 0x81], '$' MOV DX, 0x82 CALL PRINT_STRING MOV DX, offset CANT_OPEN_FILE_STR CALL PRINT_STRING JMP EXITREAD_FILE_FAIL: MOVZX BX, BYTE PTR [0x80] MOV BYTE PTR [BX + 0x81], '$' MOV DX, 0x82 CALL PRINT_STRING MOV DX, offset CANT_READ_FILE_STR CALL PRINT_STRING JMP EXITFLOPPY_WRITE_FAIL: PUSH AX MOV DX, offset CANT_WRITE_FLOPPY_STR CALL PRINT_STRING POP AX MOV AL, AH CALL PRINT_BYTE EXIT: MOV AX, 0x4C MOV AL, 0 INT 0x21.globl PRINT_STRING.type PRINT_STRING, @functionPRINT_STRING: PUSH AX MOV AH, 0x09 INT 0x21 POP AX RET .globl PRINT_CHAR.type PRINT_CHAR, @functionPRINT_CHAR: PUSH AX MOV AH, 0x02 INT 0x21 POP AX RET.globl PRINT_BYTE.type PRINT_BYTE, @functionPRINT_BYTE: PUSH AX MOV AH, AL SHR AL, 4 CMP AL, 10 JAE 1f ADD AL, '0' JMP 2f1: ADD AL, 0x372: MOV DL, AL CALL PRINT_CHAR AND AH, 0x0F CMP AH, 10 JAE 3f ADD AH, '0' JMP 4f3: ADD AH, 0x374: MOV DL, AH CALL PRINT_CHAR POP AX RET.globl PRINT_WORD.type PRINT_WORD, @functionPRINT_WORD: PUSH AX MOV AL, AH CALL PRINT_BYTE POP AX CALL PRINT_BYTE RET FILE_HANDLE:.word 0FILE_SIZE:.word 0WELCOME_STR:.ascii "REAL RAW WRITE\r\n$"NO_ARG_STR:.ascii "GIVE ME FILE NAME TO WRITE\r\n$"CANT_OPEN_FILE_STR:.ascii " - CAN'T OPEN THIS FILE\r\n$"CANT_READ_FILE_STR:.ascii " - CAN'T READ THIS FILE\r\n$"FILE_SIZE_STR:.ascii "FILE SIZE : $"SECTORS_WRITEN_STR:.ascii "h SECTORS WRITEN\r\n$"CANT_WRITE_FLOPPY_STR:.ascii "CAN'T WRITE TO FLOPPY, ERROR CODE : \r\n$"