I know that this won't have wide appeal, but here goes.
For the ports that I have done to the beeb: Asteroids, Canyon Bomber, Circus, Rip Cord, Sprint and Warlords, I use IDA Pro (from a previous employer) to disassemble the game ROM and usually do some debugging in MAME.
Since I have done all the games that I think can easily be ported without modifying the ROM other than patching on load, I now need to be able to remove chunks of unused code/data to make room or need to relocate the code as if uses &C000..&FFFF.
This that can be removed include tilt/slam sensor code, language data and low-level code to deal with the games original hardware.
Anyway, this leaves me with 6502 assembler, but not in a format that I am going to use as I don't have a suitable assembler and anyway, I really only use beebasm unless it is a very small BBC BASIC sample or loader program.
So this tool's job is to take output like:
Code: Select all
RAM:0000 byte_0: .BYTE 0 ; (uninited) ; DATA XREF: sub_64D3+38w
RAM:0000 ; sub_657C+35w ...
RAM:0001 byte_1: .BYTE 0 ; (uninited) ; DATA XREF: sub_64D3+32w
RAM:0001 ; sub_64D3+77w ...
RAM:0002 tmp_02: .BYTE 0 ; (uninited) ; DATA XREF: sub_6686+33w
RAM:0002 ; sub_6686+5Dr ...
RAM:0002 ; general use
Code: Select all
.byte_0
EQUB 0
.byte_1
EQUB 0
.tmp_02
EQUB 0
; general use
Code: Select all
IRQ_ACK:4D00 ; ===========================================================================
IRQ_ACK:4D00
IRQ_ACK:4D00 ; Segment type: Regular
IRQ_ACK:4D00 ;.segment IRQ_ACK
IRQ_ACK:4D00 * = $4D00
IRQ_ACK:4D00 irq_ack: ; 0 .BYTE uninited & unexplored ; IRQ Ack
IRQ_ACK:4D01 ; 0 .BYTE uninited & unexplored
IRQ_ACK:4D02 ; 0 .BYTE uninited & unexplored
IRQ_ACK:4D03 ; 0 .BYTE uninited & unexplored
IRQ_ACK:4D04 ; 0 .BYTE uninited & unexplored
. . .
IRQ_ACK:4DFC ; 0 .BYTE uninited & unexplored
IRQ_ACK:4DFD ; 0 .BYTE uninited & unexplored
IRQ_ACK:4DFE ; 0 .BYTE uninited & unexplored
IRQ_ACK:4DFF ; 0 .BYTE uninited & unexplored
IRQ_ACK:4DFF ; end of 'IRQ_ACK'
IRQ_ACK:4DFF
Code: Select all
ORG &4D00 ; segment IRQ_ACK
; ===========================================================================
ORG &4D00 ; segment IRQ_ACK
.irq_ack
; end of 'IRQ_ACK'
SKIP &100
ORG &5000 ; segment ROM
Code: Select all
usage: input.lst [-disable|+enable] {output.asm}
+/- a +/- check_addr + Adds a CHECK_ADDR addr between every line
+/- m +/- add_macro + Adds the CHECK_ADDR addr macro
+/- s +/- subroutine + includes " == subroutine ==" comments
+/- g +/- segment + includes "; Segment" and ";.segment" comments
+/- f +/- end_of_fun + includes "; End of function" comments
+/- c +/- comments - strips all comments not on code
+/- e +/- empty_com + includes empty comments in output
+/- t +/- tab_to_spc + changes a tab character to a space
+/- x +/- data_xref + include DATA XREF comments
+/- u +/- uninited + include (uninited) comments
Code: Select all
MACRO CHECK_ADDR ad
IF ad <> P%
PRINT CALLSTACK$
PRINT "ERROR: P% missmatch is",~P%,"should be",~ad
ENDIF
ENDMACRO
. . .
CHECK_ADDR &7FDF
BPL loc_7FBD
CHECK_ADDR &7FE1
RTS
; ---------------------------------------------------------------------------
CHECK_ADDR &7FE2
.test_grid_horz
EQUB 0,&33,&66,&99,&CC,&FF
; Vertical and horizontal positions for grid lines, stored as pointer values.
CHECK_ADDR &7FE8
.test_grid_vert
It probably doesn't matter that much as it is only really to use once.
When using it on Missile Command, it found quite a few places where there was an instruction like LDA &F0 which was in the original ROM as LDA &00F0 taking 3 bytes and an extra cycle. I added NOPs in the .LST to fix this and when everything aligned, reconverted without the MACROs and did a binary diff out the ROMs produced. They were the same apart from the NOPs and the instruction before.
An improvement would be to add a way to include a "changes" file so that the process could start from IDA Pro without having to redo changes to the .lst file, but for now, Perforce will help with that!
The project is in C++, but should be fine in a modern C compiler.
It is for Visual Studio and as such, there are a few bits to change if not using that:
#include <windows.h>
int error(const char * err)
{
fprintf(stderr, "%s(%i): error [%i]: \"%s\"+'%c' %s\n", argv1, line, colm, token, ch, err);
if (IsDebuggerPresent())
{
char error[1024];
sprintf(error, "%s(%i): error [%i]: \"%s\"+'%c' %s\n", argv1, line, colm, token, ch, err);
OutputDebugString(error);
DebugBreak();
}
return 4;
}