I am writing in m68k assembly for the sega genesis.I am using the asm68k.exe assembler. My code is as seen below ------------------ A.asm Include 'b.asm' <code> ------------------ ------------------ B.asm <code> jmp CLabel ----------------- ------------------ C.asm CLabel: Move.w #$FA14,$00000CA0 add.b #$A6,d1 ------------------ So when I assemble asm with..... asm68k.exe a.asm , a.bin It will go to a.asm , which will dump all of b .asm and into the top of a.asm... This code b.asm calls a label CLabel from c.asm, which causes an error because the assembler doesn't know what CLabel in c.asm is as it does not know about C.asm becuase the code doesn't include nor link c.asm How can I fix this ? Do I need to create an object .obj file from c.asm and let the linker use that to know what to do when b.asm jumps to CLabel? If so, how does this process work?
You pretty much answered your own question =/ So, in A.asm or B.asm, anywhere in either of these 2 asm files, include the line: Code (Text): include 'C.asm' Until you do that, it's not going to find CLabel: in C.asm, because you physically haven't told it to include C.asm. Or am I really missing your point? I only ask because you answered the question yourself...
The code comes from a zip file with all the source asm files from a tutorial on genesis programming from bigevilcorporations website. I assume due to this , the source code wil work as is ( no added includes needed) . Assuming this is the case , would I need to make c.asm a object file by assembling it and then link it to b.asm? How does this process work of so?
Personally, I still don't understand what you mean by "object file". There's no extra assembling required, all you have to do is write Code (Text): include 'C.asm' in A.asm or B.asm, as redhotsonic has already pointed out. That's it. If the source code was given to you like that, it is either broken or you're assembling from the wrong root file. Having the code in question would help here.
Or... it's done like a standard programming project, where multiple modules are separate files that are assembled and linked separately. (That's why linkers exist.) For example, in C: Code (Text): gcc -c file1.c -o file1.o gcc -c file2.c -o file2.o gcc -c file3.c -o file3.o gcc file1.o file2.o file3.o -o program file1.o, file2.o, and file3.o are all object files. The fourth command tells gcc to invoke the linker to link them all together into a single program.
Psy-Q's Saturn dev manual says there is a linker to go with ASM68K, but I have no idea where you would find it, or how you would use it.
Here is the zip file link of all asm code. Other.asm is a useless file I think. http://www.mediafire.com/download/he9919g3i0cthd4/asm_sega.zip The output file that comes with the zip is test.bin so I assume test.asm is the root . Here is test.asm Code (Text): ;assembly practice ; ; Include SEGA Genesis ROM header and CPU vector table include 'header.asm' EntryPoint: Loop: move.l #0xF, d0 ; Move 15 into register d0 move.l d0, d1 ; Move contents of register d0 into d1 jmp Loop ; Jump back up to 'Loop' HBlankInterrupt: VBlankInterrupt: rte ; Return from Exception Exception: rte ; Return from Exception __end ; Very last line, end of ROM address Here is header.asm Code (Text): ;Sega Megadrive ROM header file ;----------------------------- __Start: dc.l 0x00FFE000 ; Initial stack pointer value dc.l EntryPoint ; Start of program dc.l Exception ; Bus error dc.l Exception ; Address error dc.l Exception ; Illegal instruction dc.l Exception ; Division by zero dc.l Exception ; CHK exception dc.l Exception ; TRAPV exception dc.l Exception ; Privilege violation dc.l Exception ; TRACE exception dc.l Exception ; Line-A emulator dc.l Exception ; Line-F emulator dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Spurious exception dc.l Exception ; IRQ level 1 dc.l Exception ; IRQ level 2 dc.l Exception ; IRQ level 3 dc.l HBlankInterrupt ; IRQ level 4 (horizontal retrace interrupt) dc.l Exception ; IRQ level 5 dc.l VBlankInterrupt ; IRQ level 6 (vertical retrace interrupt) dc.l Exception ; IRQ level 7 dc.l Exception ; TRAP #00 exception dc.l Exception ; TRAP #01 exception dc.l Exception ; TRAP #02 exception dc.l Exception ; TRAP #03 exception dc.l Exception ; TRAP #04 exception dc.l Exception ; TRAP #05 exception dc.l Exception ; TRAP #06 exception dc.l Exception ; TRAP #07 exception dc.l Exception ; TRAP #08 exception dc.l Exception ; TRAP #09 exception dc.l Exception ; TRAP #10 exception dc.l Exception ; TRAP #11 exception dc.l Exception ; TRAP #12 exception dc.l Exception ; TRAP #13 exception dc.l Exception ; TRAP #14 exception dc.l Exception ; TRAP #15 exception dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.l Exception ; Unused (reserved) dc.b "SEGA GENESIS " ; Console name dc.b "(C)SEGA 1992.SEP" ; Copyrght holder and release date dc.b "Lionel Sanderson " ; Domestic name dc.b "Lionel Sanderson " ; International name dc.b "GM XXXXXXXX-XX" ; Version number dc.w 0x0000 ; Checksum dc.b "J " ; I/O support dc.l 0x00000000 ; Start address of ROM dc.l __end ; End address of ROM dc.l 0x00FF0000 ; Start address of RAM dc.l 0x00FFFFFF ; End address of RAM dc.l 0x00000000 ; SRAM enabled dc.l 0x00000000 ; Unused dc.l 0x00000000 ; Start address of SRAM dc.l 0x00000000 ; End address of SRAM dc.l 0x00000000 ; Unused dc.l 0x00000000 ; Unused dc.b " " ; Notes (unused) dc.b "JUE " ; Country codes jmp __init ;jump to the initialisation ASM file (section as its included)to prepare console prior to main code Finally here init.asm Code (Text): ;-------------------------------- ;MEGADRIVE INITIALISATION - Lionel Sanderson, 26-06-16 ;SOURCE: https://bigevilcorporation.co.uk/2012/03/09/sega-megadrive-3-awaking-the-beast/ ;-------------------------------- __init: ;============================= ;1. Checking the Reset Button ;============================= EntryPoint: ; Entry point address set in ROM header tst.w 0x00A10008 ; Test mystery reset (expansion port reset?) bne Main ; Branch if Not Equal (to zero) - to Main tst.w 0x00A1000C ; Test reset button bne Main ; Branch if Not Equal (to zero) - to Main ;========================= ;2. Clearing the RAM ;========================= move.l #0x00000000, d0 ; Place a 0 into d0, ready to copy to each longword of RAM move.l #0x00000000, a0 ; Starting from address 0x0, clearing backwards move.l #0x00003FFF, d1 ; Clearing 64k's worth of longwords (minus 1, for the loop to be correct) @Clear: move.l d0, -(a0) ; Decrement the address by 1 longword, before moving the zero from d0 to it dbra d1, @Clear ; Decrement d0, repeat until depleted ;========================= ;3. Writing the TMSS ;========================= ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;the Trade Mark Security Signature – or TMSS – was a feature put in by Sega to combat unlicensed developers from releasing games for their system, ;which is a kind of killswitch for the VDP. It's the pinnacle of security systems, a very sophisticated encryption key which is almost uncrackable. ;You write the string “SEGA” to 0x00A14000. ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< move.b 0x00A10001, d0 ; Move Megadrive hardware version to d0 andi.b #0x0F, d0 ; The version is stored in last four bits, so mask it with 0F https://en.wikipedia.org/wiki/Mask_%28computing%29 beq @Skip ; If version is equal to 0, skip TMSS signature move.l #'SEGA', 0x00A14000 ; Move the string "SEGA" to 0xA14000 @Skip: ;============================ ;4. Initialising the Z80 ;============================ move.w #0x0100, 0x00A11100 ; Request access to the Z80 bus, by writing 0x0100 into the BUSREQ port move.w #0x0100, 0x00A11200 ; Hold the Z80 in a reset state, by writing 0x0100 into the RESET port @Wait: btst #0x0, 0x00A11100 ; Test bit 0 of A11100 to see if the 68k has access to the Z80 bus yet bne @Wait ; If we don't yet have control, branch back up to Wait ;Here's a new opcode, BTST (bit test). It does the same as TST, but only compares the least significant bits. ;Now the 68000 has access to the Z80's bus, and the chip is held in a reset state, so we can write the program data to its memory. This is mapped from 0xA000000. move.l #Z80Data, a0 ; Load address of data into a0 move.l #0x00A00000, a1 ; Copy Z80 RAM address to a1 move.l #0x29, d0 ; 42 bytes of init data (minus 1 for counter) @CopyZ80: move.b (a0)+, (a1)+ ; Copy data, and increment the source/dest addresses dbra d0, @CopyZ80 move.w #0x0000, 0x00A11200 ; Release reset state move.w #0x0000, 0x00A11100 ; Release control of bus ; ===================================================== ;5. Initialising the PSG (programmable sound generator) ;====================================================== move.l #PSGData, a0 ; Load address of PSG data into a0 move.l #0x03, d0 ; 4 bytes of data @CopyPSG: move.b (a0)+, 0x00C00011 ; Copy data to PSG RAM dbra d0, @CopyPSG ;======================== ;6. Initialising the VDP ;======================== move.l #VDPRegisters, a0 ; Load address of register table into a0 move.l #0x18, d0 ; 24 registers to write move.l #0x00008000, d1 ; 'Set register 0' command (and clear the rest of d1 ready) @CopyVDP: move.b (a0)+, d1 ; Move register value to lower byte of d1 move.w d1, 0x00C00004 ; Write command and value to VDP control port add.w #0x0100, d1 ; Increment register # dbra d0, @CopyVDP ;====================================== ;7. Initialising the Controller Ports ;====================================== ;The controller ports are generic 9-pin I/O ports, and are not particularly tailored to any device. They have five mapped I/O address each – CTRL, DATA, TX, RX and S-CTRL: ; ; CTRL controls the I/O direction and enables/disables interrupts generated by the port ; DATA is used to send/receive data to or from the port (in bytes or words) when the port is in parallel mode ; TX and RX are used to send/receive data in serial mode ; S-CTRL is used to get/set the port's current status, baud rate and serial/parallel mode. ; Set IN I/O direction, interrupts off, on all ports move.b #0x00, 0x000A10009 ; Controller port 1 CTRL move.b #0x00, 0x000A1000B ; Controller port 2 CTRL move.b #0x00, 0x000A1000D ; EXP port CTRL ;========================================= ;8. Clearing the Registers and Tidying Up ;========================================= move.l #0x00000000, a0 ; Move 0x0 to a0 movem.l (a0), d0-d7/a1-a7 ; Multiple move 0 to all registers ;Here's a very useful opcode – MOVEM (move multiple). It can move data to/from a list of registers or register ranges, ;for example d0,d3,d5 or a3-a5. A common use for it would be to backup/restore all of the registers to/from the stack, in a single instruction. ;================ ;status register ;================ ; Init status register (no trace, A7 is Interrupt Stack Pointer, no interrupts, clear condition code bits) move #0x2700, sr jmp __main ; Jump to the game code!
Seems to be MAIN.ASM from here. At least then I get the build to fully run and receive a playable ROM.
It seems that the associated linker for asm68k would be lnk68k, but good luck finding it. Without a linker, your only option is basically having a top-level .asm that includes all the other ones, e.g. how main.asm is setup in the ZIP file you uploaded.
The problem explained earlier occurs in header.asm at the very bottom of the file when it jmp to label _init which is in Init.asm . It has no clue what _init is . Assuming the code works as is , not including init.as , are their any solutions ? Also do include directives in 68k simply dump the code into memory at the point the directive include <file> is writen? Also are their a way to include a label without going to that label ... Like just have a declarations it knows what it is like in c?
There's no linker available. You have to have all the .asm files included from a top-level file, and then assemble the top-level one. Init.asm hence has to be included from the file that also includes header.asm. The include directive in asm works exactly the same as in C; it acts like the contents of the file to be included are located at that point in the main file.
I haven't actually used a linker for MD games, precisely because there isn't one that's generally available and easy to integrate. (The GNU linker doesn't work too well because it generates ELF binaries, not raw ROM images.) Last time I did anything related to MD assembly, I used asmx-2.0b5. However, switching assemblers isn't going to solve the problem you're having. Once again, you *must* include all .asm files from the top-level (or include them from included asm files); otherwise, they won't assemble and you'll run into unresolved symbol errors.
Selbi many thankamthats an easy fix. I was assuming the tutorial assumed the users knew they had to do extra stuff monkeying around . /> ;p
Thanks Selbi Getbalsoft Main Memory Redhotsonic Neo!! /> On the subject of include directives, can you include an assemby file that just tells you what the first label in the codes implementation IS (declaration / definition) but not have it go to this first label when in includes this asm file? In other words, can you just have it be their waiting for when u jmp to on Lea a label it will know what to do and at the end of the label it will return to subroutine rts ?
As far as I am aware, BigEvilCorp is a total assembly noob, and I wouldn't take what he tells without a grain of salt. Now I am not sure what you mean with this last post, but if you mean something vaguely to do with defining a routine without actually having one, you can do it, but you need to be really careful with it, unless you want your code to jump to bad offsets that is. You can do something along the lines of this in asm68k: Code (Text): Lable equ $FF00 This will create a symbolic link to lable at address 0xFF00, and will allow your code to target this as if it was just any lable you would define normally.
That blog was written back when I was learning the language, and it's not a "tutorial", more a log of my learning experiences to help me remember, so yes indeed take everything you read there with a huge grain of salt. As for your test.asm issue - assembling that file isn't enough, since it doesn't include the rest of the code. You need to assemble main.asm, which includes both header.asm and init.asm in appropriate locations. I'm not sure where that test.asm came from either, it's not something I wrote. A few people have sent me various ZIP files with their own code that I've fixed up and sent back, was this one of yours? It's probably about time I revisited that site and cleaned everything up into proper, fact checked tutorials, now that I know what I'm doing Too many people seem to relying on those posts as gospel, they were written by a noob and they're riddled with mistakes.