From 4564c7906be89463b8f9637685e1785dd900f4b3 Mon Sep 17 00:00:00 2001 From: Ian C Date: Wed, 16 Mar 2016 11:31:21 +0000 Subject: Updated banking to work with output. --- doc/Makefile | 4 +- doc/manual.asciidoc | 27 +- doc/manual.html | 1600 --------------------------------------------------- doc/manual.pdf | Bin 148743 -> 0 bytes src/casm.c | 23 + src/output.c | 111 ++-- src/state.c | 68 ++- src/state.h | 13 +- 8 files changed, 168 insertions(+), 1678 deletions(-) delete mode 100644 doc/manual.html delete mode 100644 doc/manual.pdf diff --git a/doc/Makefile b/doc/Makefile index 0791d55..9fb7486 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -26,7 +26,7 @@ manual.html: manual.asciidoc asciidoc manual.asciidoc manual.pdf: manual.asciidoc - a2x -fpdf -dbook manual.asciidoc + a2x manual.asciidoc clean: - rm -f manual.html manual.pdf + rm -f manual.html manual.pdf manual.xml diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc index 99d07f6..3a20b69 100644 --- a/doc/manual.asciidoc +++ b/doc/manual.asciidoc @@ -29,6 +29,13 @@ casm file Assembles file, and places the output in _output_ by default. +Memory Layout +------------- + +There is 64K of RAM that the assembler will generate output into. Extra 64K +banks of RAM can be added by using the 'bank' or 'org' directives. Banks are +numbered from zero upwards. + Source Format Example --------------------- @@ -111,8 +118,13 @@ equ _value_:: Sets the top level label to _value_. Note this requires a label on the same line. -org _value_:: - Sets the program counter (PC) to _value_. The PC defaults to zero. +org _value_[,_bank_]:: + Sets the program counter (PC) to _value_. The PC defaults to zero. If the + optional second argument is passed the current memory bank in use is set + to _bank_. + +bank _value_:: + The current memory bank in use is set to _value_. ds _value_[, _fill_]:: Skips on the program counter _value_ bytes. If the optional _fill_ is @@ -371,12 +383,15 @@ Output Format ------------- By default the assembled code is written to a file called *output* as raw -binary covering the block of memory that the assembly touched. +binary covering the block of memory that the assembly touched. If memory +banks have been used then *output* is appended with the memory bank number, so +that a separate output file is generated for each bank. This can be controlled with the following options. option output-file, _file_:: - Send the output to _file_. + Send the output to _file_. If memory banks have been used then files are + generated with the names _file_.0, _file_.1, and so on. option output-type, _format_:: Controls the output format with the following settings @@ -389,7 +404,9 @@ option output-type, _format_:: be given the same name as the output filename, and its load address will be set to the start of the created memory. Remember that TAP files can be concatenated, so the output could be appended to - another TAP file containing a BASIC loader for example. + another TAP file containing a BASIC loader for example. Note that + if memory banks have been used then each bank is output to the TAP + file as separate code blocks. Listing diff --git a/doc/manual.html b/doc/manual.html deleted file mode 100644 index c25be2e..0000000 --- a/doc/manual.html +++ /dev/null @@ -1,1600 +0,0 @@ - - - - - -CASM - - - - - -
-
-
-

A simple, portable multi-pass assembler

-

Copyright © 2003-2015 Ian Cowburn <ianc@noddybox.co.uk>

-

This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version.

-

This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details.

-

You should have received a copy of the GNU General Public License -along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0.html

-
-
-
-

Usage

-
-
-
-
casm file
-
-

Assembles file, and places the output in output by default.

-
-
-
-

Source Format Example

-
-

The source files follow this basic format:

-
-
-
; Comments
-;
-label1: equ     0xffff
-
-        org     $4000;
-
-        db      "Hello, World\n",0
-
-main    jp      local_label     ; Comments
-
-.local_label
-        inc     a
-
-another:
-        inc     b
-        jp      local_label     ; Actually jumps to the following local_label.
-
-.local_label
-        ret
-
-

The source files follow the following rules:

-
    -
  • -

    -Any text past a semicolon (;) is discarded as a comment (except when part - of a string constant). -

    -
  • -
  • -

    -Labels must start in column zero (the left hand most column). -

    -
      -
    • -

      -If the label ends with a colon (:) then the colon is removed. -

      -
    • -
    • -

      -If the label doesn’t start with a period (.) then it is assumed a global - label. -

      -
    • -
    • -

      -If the label starts with a period (.) then it is assumed to be a local - label. Local labels are associated with the preceding global label. If a - global label and related local label have the same name, the local label - will be used on expansion. -

      -
    • -
    • -

      -Any label can be followed by an equ directive, in which case the label - is set to that value rather than the current program counter. -

      -
    • -
    • -

      -Labels are case-insensitive. -

      -
    • -
    -
  • -
  • -

    -Directives and opcodes must appear further along the line (anywhere else - other than the left hand column where labels live basically). -

    -
  • -
  • -

    -Strings can either be quoted with single or double quotes; this allows you to - put the other quote type inside the string. -

    -
  • -
-
-

Recognised directives

-

All directives are also recognised with an optional period (.) in front of -them, and are case insensitive. Directives can also be used to control the -output of a program listing, and the output of the assembly itself. These are -documented in further sections.

-
-
-processor CPU -
-
-

- Sets the processor type to CPU. If omitted then Z80 is the default. - Note that this can appear multiple times in the same file. Currently - supported CPU values are Z80 and 6502. -

-
-
-option setting, value -
-
-

- Set options. Options are defined later on, and each CPU can also have its - own options. For options that support booleans (on/off/true/false), - the setting can be prefixed with a plus or minus character to switch it - on or off respectively. -

-
-
-equ value -
-
-

- Sets the top level label to value. Note this requires a label on the - same line. -

-
-
-org value -
-
-

- Sets the program counter (PC) to value. The PC defaults to zero. -

-
-
-ds value[, fill] -
-
-

- Skips on the program counter value bytes. If the optional fill is - provided then the bytes are filled with fill, otherwise they are filled - with zero. -

-
-
-db value[, value] -
-
-

- Writes bytes to the current PC. The values can be constants, expressions, - labels or strings. Built-in aliases are byte and text. -

-
-
-dw <value>[, <value>] -
-
-

- Writes words (16-bit values) to the current PC. The values can be - constants, expressions or labels. Note that word is a built-in alias for - this directive. -

-
-
-align value[, fill] -
-
-

- Align the PC so that (PC modulus value) is zero. Will error if value - is less than 2 or greater that 32768. No values are written to the skipped - bytes unless the optional fill is supplied. -

-
-
-include filename -
-
-

- Includes the source file filename as if it was text entered at the - current location. -

-
-
-incbin filename -
-
-

- Includes the binary data in filename at the current PC, as if it was a - sequence of db directives with all the bytes from the file. -

-
-
-alias command, replacement -
-
-

- Creates an alias so that whenever the command command is found in the - source it is replaced with replacement. The idea of this is to make it - easier to import sources that use unknown directives, e.g. -

-
-
-
alias setaddr,org
-alias ldreg,ld
-
-
-
-
cpu         z80
-
-
-
-
setaddr     $8000   ; These two are
-org         $8000   ; equivalent.
-
-
-
-
ld          a,(hl)  ; These two are
-ldreg       a,(hl)  ; equivalent.
-
-
-
-nullcmd -
-
-

- Simply does nothing. It’s only real use is as an alias if you wished to - strip a directive from a foreign source file. -

-
-
-end -
-
-

- Terminates the input processing. Anything past the directive will be - ignored. -

-
-
-
-
-

Expressions

-

In any of the directives above, where a value is defined, an expression can be -entered.

-

The following formats for constant numbers are supported (note these are -illustrated as a regular expression):

-
-
-"x" or x -
-
-

- A single quoted character will be converted into the appropriate character - code. -

-
-
-[1-9][0-9]* -
-
-

- A decimal number, e.g. 42. -

-
-
-0[0-7]* -
-
-

- An octal number, e.g. 052. -

-
-
-0x[0-9a-fA-f]+ -
-
-

- A hex number, e.g. 0x2a. -

-
-
-[0-9a-fA-f]+h -
-
-

- A hex number, e.g. 2ah. -

-
-
-$[0-9a-fA-f]+ -
-
-

- A hex number, e.g. $2a. -

-
-
-[01]+b -
-
-

- A binary number, e.g. 00101010b -

-
-
-[a-zA-Z_0-9]+ -
-
-

- A label, e.g. main_loop. -

-
-
-

The following operators are understood. The order here is the order of -precedence.

-
-
-{ } -
-
-

- Brackets used to alter the order of precedence. Note normal parenthesis - aren’t used as the assembly language may make use of them. -

-
-
-~ + - -
-
-

- Bitwise NOT/unary plus/unary minus. -

-
-
-<< >> -
-
-

- Shift left/shift right. -

-
-
-/ * % -
-
-

- Division/multiplication/modulus. -

-
-
-+ - -
-
-

- Addition/subtraction. -

-
-
-

All the following have the same precedence, and so will be done left to right.

-
-
-== -
-
-

- Equality. Returns 1 if the arguments are equal, otherwise zero. -

-
-
-!= -
-
-

- Inequality. Returns 1 if the arguments are unequal, otherwise zero. -

-
-
-< <= > >= -
-
-

- Less than/less than or equal/greater than/greater than or equal. Returns 1 - if the arguments are equal, otherwise zero. -

-
-
-

All the following have the same precedence, and so will be done left to right.

-
-
-&& & -
-
-

- Boolean/bitwise AND. For boolean operation arguments, zero is FALSE, - otherwise TRUE. -

-
-
-|| | -
-
-

- Boolean/bitwise OR. -

-
-
-^ -
-
-

- Bitwise XOR. -

-
-
-

Assembly instructions will also permit these expressions to be used where -applicable. As many opcodes use parenthesis to indicate addressing modes, -remember that {} brackets can be used to alter expression precedence.

-
-
-
    ld  a,{8+2}*2               ; On the Z80 loads A with the value 20
-    ld  a,({8+2}*2)             ; On the Z80 loads A with the value stored at
-                                ; address 20
-
-

Note that the expression is evaluated using a standard C int, and then cast -to the appropriate size.

-
-
-

Character Sets

-

The assembler has built-in support for a few different character sets. -These can be set by using the options charset or codepage, i.e.

-
-
-
    option codepage, <format>
-    option charset, <format>
-
-

The following values can be used for format.

-
-
-ascii -
-
-

- 7-bit ASCII. This is the default. -

-
-
-spectrum -
-
-

- The character codes as used on the Sinclair ZX Spectrum. -

-
-
-zx81 -
-
-

- The character codes as used on the Sinclair ZX-81. Lower case - letters are encoded as normal upper case letters and upper case - letter will be encoded as inverse upper case letters. -

-
-
-cbm -
-
-

- PETSCII as used on the Commodore Business Machine’s range from the - PET to the C128. See https://en.wikipedia.org/wiki/PETSCII for - more details. -

-
-
-

e.g.

-
-
-
    option  +list
-    option  +list-hex
-
-    option  charset,ascii
-    db      "Hello",'A'
-; $48 $65 $6C $6C $6F $41
-
-    option  charset,zx81
-    db      "Hello",'A'
-; $AD $2A $31 $31 $34 $A6
-
-    option  codepage,cbm
-    db      "Hello",'A'
-; $48 $45 $4C $4C $4F $41
-
-    option  codepage,spectrum
-    db      "Hello",'A'
-; $48 $65 $6C $6C $6F $41
-
-
-
-

Macros

-

Macros can be defined in one of two ways; either parameterless or with named -parameters. Macro names are case-insensitive. In the parameterless mode the -special identifier * can be used to expand all arguments, which will be -separated with commas.

-
-
-
macro1: macro
-
-        ld a,\1
-        ld b,\2
-        call \3
-        defb \*
-
-        endm
-
-macro2: macro char,junk,interface
-
-        ld a,@char
-        ld b,@junk
-        call @interface
-
-        endm
-
-

Note that trying to expand and unknown/missing argument will be replaced with -an empty string. Also the two argument reference styles can be mixed, though -obviously the @ form only makes sense in a parameterised macro, e.g.

-
-
-
mac:    macro char,junk,interface
-
-        ld a,@char
-        ld b,\2
-        call @interface
-
-        endm
-
-

The at symbol (@) used for parameter expansion in named argument macros can -be replaced by using the following option, e.g.

-
-
-
        option  macro-arg-char,&
-
-

Note that this is enforced when the macro is used, not when it is defined. -Also the character must not be quoted, as that will be parsed as a string -holding the character code of the character.

-
-
-
-
-

Output Format

-
-

By default the assembled code is written to a file called output as raw -binary covering the block of memory that the assembly touched.

-

This can be controlled with the following options.

-
-
-option output-file, file -
-
-

- Send the output to file. -

-
-
-option output-type, format -
-
-

- Controls the output format with the following settings -

-
-
-raw -
-
-

- The default raw binary. -

-
-
-spectrum -
-
-

- Generates a Spectrum TAP file for an emulator. The TAP file will - be given the same name as the output filename, and its load address - will be set to the start of the created memory. Remember that TAP - files can be concatenated, so the output could be appended to - another TAP file containing a BASIC loader for example. -

-
-
-
-
-
-
-
-

Listing

-
-

By default no output listing is generated. This can be controlled by the -the following options.

-
-
-option list, <on|off> -
-
-

- Enables/disables listing. The listing will go to stdout. -

-
-
-option list-file, file -
-
-

- Sends the listing to file. Note this should appear before enabling the - listing. -

-
-
-option list-pc, <on|off> -
-
-

- Control the output of the current PC in the as a comment preceding the - line (so that a listing could be reassembled with no editing). Defaults - to off. -

-
-
-option list-hex, <on|off> -
-
-

- Control the output of the bytes generated by the source line in hex. - Defaults to off. If on then the hex is output in a comment preceding - the line (possibly with the PC above), so that a listing is still valid to - be assembled. -

-
-
-option list-labels, <on|off|all> -
-
-

- Controls the listing of labels, either off (the default), on to dump - label values at the end of the listing and all to dump all labels, - including internally generated private labels for macros. -

-
-
-option list-macros, <off|exec|dump|all> -
-
-

- Controls the listing of macro invocations, either -

-
-
-off -
-
-

- The default; don’t list anything. -

-
-
-exec -
-
-

- List invocations of macros. -

-
-
-dump -
-
-

- Produce a list of macro definitions at the end of the listing. -

-
-
-all -
-
-

- Combine "exec" and "dump" -

-
-
-
-
-option list-rm-blanks, <on|off> -
-
-

- Defaults to on. This option causes multiple blank lines to be collapsed - down to a single line. -

-
-
-
-
-
-

Z80 CPU

-
-
-

Opcodes

-

The Z80 assembler uses the standard Zilog opcodes, and supports -undocumented instructions.

-

For instructions were the Accumulator can be assumed it can be omitted, and -EOR can be used the same as XOR:

-
-
-
    xor     a,a         ; These are equivalent
-    xor     a
-    eor     a,a
-
-    and     a,b         ; These are equivalent
-    and     b
-
-

For exchange opcodes with parameters the parameters can be reversed from their -official form:

-
-
-
    ; The official forms
-    ;
-    ex      de,hl
-    ex      af,af'
-    ex      (sp),hl
-    ex      (sp),ix
-    ex      (sp),iy
-
-    ; Also supported
-    ;
-    ex      hl,de
-    ex      af',af
-    ex      hl,(sp)
-    ex      ix,(sp)
-    ex      iy,(sp)
-
-

Where the high/low register parts of the IX and IY registers are to be used, -simply use ixl, iyl, ixh and iyh. Note that the assembler will accept -illegal pairings involving H and L, but these will be warned about:

-
-
-
    ld  ixh,$e5
-    ld  iyl,iyl
-
-    ld  ixh,l           ; This will be turned into "ld ixh,ixl" and a
-                        ; warning will be issued.
-
-    ld  iyh,ixl         ; This will generate an error as the index registers
-                        ; have been mixed.
-
-

For bit manipulations that also can copied to a register, these can be -represented by adding the destination register as an extra parameter, e.g.

-
-
-
    srl (iy-1),d
-    set 3,(iy-1),a
-    res 4,(iy-1),b
-
-

For the hidden IN instruction using the flag register the following are all -equivalent:

-
-
-
    in  (c)
-    in  f,(c)
-
-

For the hidden OUT instruction using the flag register, $00 or $ff depending -on where you’re reading, the following are all equivalent, where value can -be any value at all:

-
-
-
    out (c)
-    out (c),f
-    out (c),<value>
-
-
-
-

Options

-

The Z80 assembler has no options.

-
-
-
-
-

6502 CPU

-
-
-

Opcodes

-

The 6502 assembler uses the standard Motorola opcodes.

-
-
-

Options

-

The 6502 assembler has the following options.

-
-
-option zero-page, <on|off|auto> -
-
-

- Use Zero-Page addressing for absolute and absolute,X address modes. - If mode is set to auto then tries to calculate the mode based on the - value in the last pass. - Defaults to off. e.g. -

-
-
-
cpu     6502
-org     $8000
-
-
-
-
lda     $0000,x     ; Produces $bd $00 $00
-option  +zero-page
-lda     $0000,x     ; Produces $b5 $00
-lda     $1234,x     ; Produces an error
-
-
-
-
option  zero-page,auto
-lda     $00,x       ; Produces $b5 $00
-lda     $8000,x     ; Produces $bd $00 $80
-
-
-
-
-
-
-
-

- - - diff --git a/doc/manual.pdf b/doc/manual.pdf deleted file mode 100644 index 5cd5ea7..0000000 Binary files a/doc/manual.pdf and /dev/null differ diff --git a/src/casm.c b/src/casm.c index 9f685f8..1340eb7 100644 --- a/src/casm.c +++ b/src/casm.c @@ -139,6 +139,27 @@ static CommandStatus ORG(const char *label, int argc, char *argv[], LabelSet(label, result, ANY_LABEL); } + /* See if an optional bank was supplied + */ + if (argc > 2) + { + CMD_EXPR(argv[2], result); + SetAddressBank(result); + } + + return CMD_OK; +} + +static CommandStatus BANK(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + int result; + + CMD_ARGC_CHECK(2); + CMD_EXPR(argv[1], result); + + SetAddressBank(result); + return CMD_OK; } @@ -410,6 +431,8 @@ static struct {".eq", EQU}, {"org", ORG}, {".org", ORG}, + {"bank", BANK}, + {".bank", BANK}, {"ds", DS}, {".ds", DS}, {"defs", DS}, diff --git a/src/output.c b/src/output.c index ccad6af..13a7809 100644 --- a/src/output.c +++ b/src/output.c @@ -65,20 +65,43 @@ static ValueTable format_table[] = /* ---------------------------------------- PRIVATE FUNCTIONS */ -static int OutputRawBinary(const Byte *mem, int min, int max) +static int OutputRawBinary(MemoryBank **bank, int count) { - FILE *fp = fopen(output, "wb"); + char buff[4096]; + int f; - if (!fp) + for(f = 0; f < count; f++) { - snprintf(error, sizeof error,"Failed to open %s\n", output); - return FALSE; + FILE *fp; + const char *name; + const Byte *mem; + int min, max; + + if (count == 1) + { + name = output; + } + else + { + snprintf(buff, sizeof buff, "%s.%u", output, bank[f]->number); + name = buff; + } + + if (!(fp = fopen(name, "wb"))) + { + snprintf(error, sizeof error,"Failed to open %s\n", name); + return FALSE; + } + + mem = bank[f]->memory; + min = bank[f]->min_address_used; + max = bank[f]->max_address_used; + + fwrite(mem + min, 1, max - min + 1, fp); + + fclose(fp); } - fwrite(mem + min, 1, max - min + 1, fp); - - fclose(fp); - return TRUE; } @@ -110,11 +133,10 @@ static Byte TapString(FILE *fp, const char *p, int len, Byte chk) } -static int OutputSpectrumTap(const Byte *mem, int min, int max) +static int OutputSpectrumTap(MemoryBank **bank, int count) { FILE *fp = fopen(output, "wb"); - Byte chk = 0; - int len = max - min + 1; + int f; if (!fp) { @@ -124,32 +146,44 @@ static int OutputSpectrumTap(const Byte *mem, int min, int max) /* Output header */ - TapWord(fp, 19, 0); + for(f = 0; f < count; f++) + { + Byte chk = 0; + const Byte *mem; + int min, max, len; - chk = TapByte(fp, 0, chk); - chk = TapByte(fp, 3, chk); - chk = TapString(fp, output, 10, chk); - chk = TapWord(fp, len, chk); - chk = TapWord(fp, min, chk); - chk = TapWord(fp, 32768, chk); + mem = bank[f]->memory; + min = bank[f]->min_address_used; + max = bank[f]->max_address_used; + len = max - min + 1; - TapByte(fp, chk, 0); + TapWord(fp, 19, 0); - /* Output file data - */ - TapWord(fp, len + 2, 0); + chk = TapByte(fp, 0, chk); + chk = TapByte(fp, 3, chk); + chk = TapString(fp, output, 10, chk); + chk = TapWord(fp, len, chk); + chk = TapWord(fp, min, chk); + chk = TapWord(fp, 32768, chk); - chk = 0; + TapByte(fp, chk, 0); - chk = TapByte(fp, 0xff, chk); + /* Output file data + */ + TapWord(fp, len + 2, 0); - while(min <= max) - { - chk = TapByte(fp, mem[min], chk); - min++; - } + chk = 0; + + chk = TapByte(fp, 0xff, chk); + + while(min <= max) + { + chk = TapByte(fp, mem[min], chk); + min++; + } - TapByte(fp, chk, 0); + TapByte(fp, chk, 0); + } fclose(fp); @@ -193,30 +227,27 @@ CommandStatus OutputSetOption(int opt, int argc, char *argv[], int OutputCode(void) { - const MemoryBank *bank = MemoryBanks(); + MemoryBank **bank; + int count; int min; int max; const Byte *mem; + bank = MemoryBanks(&count); + if (!bank) { fprintf(stderr, "Skipping output; no written memory to write\n"); return TRUE; } - /* TODO: Fix to pass banks proper - */ - min = bank[0].min_address_used; - max = bank[0].max_address_used; - mem = bank[0].memory; - switch(format) { case Raw: - return OutputRawBinary(mem, min, max); + return OutputRawBinary(bank, count); case SpectrumTap: - return OutputSpectrumTap(mem, min, max); + return OutputSpectrumTap(bank, count); default: break; diff --git a/src/state.c b/src/state.c index 32fa6b3..27225e5 100644 --- a/src/state.c +++ b/src/state.c @@ -38,40 +38,50 @@ static int pass = 1; static int maxpass = 2; static int pc = 0; +static int num_banks = 0; static unsigned currbank = 0; static WordMode wmode = LSB_Word; -static MemoryBank *bank; +static MemoryBank **bank; static MemoryBank *current; /* ---------------------------------------- PRIVATE */ +static int SortBank(const void *a, const void *b) +{ + const MemoryBank *ma = a; + const MemoryBank *mb = b; + + return (int)ma->number - (int)mb->number; +} + + static void RemoveBanks(void) { - while(bank) - { - MemoryBank *t = bank->next; + int f; - free(bank); - bank = t; + for(f = 0; f < num_banks; f++) + { + free(bank[f]); } - current = NULL; + free(bank); + currbank = 0; + bank = NULL; + current = NULL; } static MemoryBank *FindBank(unsigned n) { - MemoryBank *t = bank; + int f; - while(t) + for(f = 0; f < num_banks; f++) { - if (t->number == n) + if (bank[f]->number == n) { - return t; + return bank[f]; } - - t = t->next; } return NULL; @@ -79,28 +89,27 @@ static MemoryBank *FindBank(unsigned n) static void ClearBankWriteMarkers(void) { - MemoryBank *t = bank; + int f; - while(t) + for(f = 0; f < num_banks; f++) { - t->min_address_used = BANK_SIZE; - t->max_address_used = -1; - t = t->next; + bank[f]->min_address_used = BANK_SIZE; + bank[f]->max_address_used = -1; } } static MemoryBank *AddBank(unsigned n) { - MemoryBank *t = Malloc(sizeof *t); + current = NULL; + num_banks++; - t->min_address_used = BANK_SIZE; - t->max_address_used = -1; - t->number = n; + bank = Realloc(bank, (sizeof *bank) * num_banks); + bank[num_banks-1] = Malloc(sizeof **bank); + bank[num_banks-1]->number = n; - t->next = bank; - bank = t; + qsort(bank, num_banks, sizeof *bank, SortBank); - return t; + return FindBank(n); } static MemoryBank *GetOrAddBank(unsigned n) @@ -168,6 +177,7 @@ void SetNeededPasses(int n) void SetAddressBank(unsigned b) { currbank = b; + current = NULL; } @@ -257,8 +267,9 @@ void PCWriteWordMode(int i, WordMode mode) } -const MemoryBank *MemoryBanks(void) +MemoryBank **MemoryBanks(int *count) { + *count = num_banks; return bank; } @@ -267,6 +278,11 @@ Byte ReadByte(int addr) { Byte b = 0; + if (!current) + { + current = GetOrAddBank(currbank); + } + if (addr > -1 && addr < BANK_SIZE && current) { b = current->memory[addr]; diff --git a/src/state.h b/src/state.h index e10463c..247124f 100644 --- a/src/state.h +++ b/src/state.h @@ -39,13 +39,12 @@ typedef enum } WordMode; -typedef struct mbnk +typedef struct { unsigned number; /* The bank number, 0 .. n */ Byte memory[BANK_SIZE]; /* The memory in that bank */ int min_address_used; /* Will be BANK_SIZE if not used */ int max_address_used; /* Will be -1 if not used */ - struct mbnk *next; /* The next memory bank */ } MemoryBank; /* ---------------------------------------- INTERFACES @@ -119,10 +118,14 @@ void PCWriteWord(int i); void PCWriteWordMode(int i, WordMode mode); -/* Gets a list of the banks used. A NULL return means no memory was written - to at all. +/* Gets a list of the banks used as an array of pointers. A NULL return means + no memory was written to at all. + + *count will be updated with the number of banks used, or zero if no memory + was written to. Note that banks may not be contiguously numbered, but will + be in ascending order. */ -const MemoryBank *MemoryBanks(void); +MemoryBank **MemoryBanks(int *count); /* Read a byte from the current bank. -- cgit v1.2.3