/* hp3000_mem.h: HP 3000 memory subsystem interface declarations

   Copyright (c) 2016, J. David Bryan

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the author shall not be used
   in advertising or otherwise to promote the sale, use or other dealings in
   this Software without prior written authorization from the author.

   10-Oct-16    JDB     Created


   This file contains declarations used by the CPU, I/O Processor, Multiplexer
   Channel, and Selector Channel to interface with the HP 3000 memory subsystem.
*/



/* Debug flags.


   Implementation notes:

    1. Memory debug flags are allocated in descending order, as they may be used
       by other modules (e.g., CPU) that allocate their own flags in ascending
       order.  No check is made for overlapping values.
*/

#define DEB_MDATA           (1u << 31)          /* trace memory reads and writes */
#define DEB_MFETCH          (1u << 30)          /* trace memory instruction fetches */
#define DEB_MOPND           (1u << 29)          /* trace memory operand accesses */


/* Architectural constants.

   The type used to represent a main memory word value is defined.  An array of
   this type is used to simulate the CPU main memory.


   Implementation notes:

    1. The MEMORY_WORD type is a 16-bit unsigned type, corresponding with the
       16-bit main memory in the HP 3000.  Unlike the general data type, which
       is a 32-bit type for speed, main memory does not benefit from the faster
       32-bit execution on IA-32 processors, as only one instruction in the
       cpu_read_memory and cpu_write_memory routines has an operand override
       that invokes the slower instruction fetch path.  There is a negligible
       difference in the Memory Pattern Test diagnostic execution speeds for the
       uint32 vs. uint16 definition, whereas the VM requirements are doubled for
       the former.
*/

typedef uint16              MEMORY_WORD;        /* HP 16-bit memory word representation */


/* Byte accessors.

   The HP 3000 is a word-addressable machine.  Byte addressing is implemented by
   assuming that a memory of N physical words may be addressed as 2N bytes.  The
   "byte-capable" machine instructions use "relative byte addresses" that are
   used to obtain absolute word addresses by dividing by two and then accessing
   the upper or lower byte of the resulting word, depending on the LSB of the
   byte address.

   In simulation, this module provides a byte access structure and a set of
   routines that read or write the next byte in ascending byte-offset order.
   The structure is initialized with the starting byte offset from a specified
   base register value and then is passed as a parameter to the other routines,
   which update the fields accordingly for the access requested.  This relieves
   the caller from having to manage the continual logical-to-physical address
   translation, word buffering, byte selection, etc.

   Byte accessors are also used to provide debug traces of byte operands in
   memory.  Initializing an accessor sets a field containing the absolute byte
   memory address; this address may be passed to the byte formatters to print
   the operand.

   In most cases, operands are defined by starting byte addresses and byte
   counts.  However, some operands (e.g., EDIT instruction operands) are
   delineated only by the extents of the accesses.  For these operands, byte
   accessors maintain the lowest byte addresses and offsets actually accessed,
   as well as the lengths of the extent of the accesses.
*/

typedef struct {                                        /* byte access descriptor */
    HP_WORD       *byte_offset;                         /*   relative byte offset of the next byte */
    HP_WORD       data_word;                            /*   memory data word containing the current byte */
    ACCESS_CLASS  class;                                /*   memory access classification */
    uint32        word_address;                         /*   logical word address containing the next byte */
    t_bool        write_needed;                         /*   TRUE if the data word must be written to memory */
    uint32        count;                                /*   current count of bytes accessed */
    uint32        length;                               /*   (trace) length of extent of access */
    uint32        initial_byte_address;                 /*   (trace) initial absolute byte address */
    uint32        initial_byte_offset;                  /*   (trace) initial relative byte offset */
    uint32        first_byte_address;                   /*   (trace) lowest absolute byte address accessed */
    uint32        first_byte_offset;                    /*   (trace) lowest relative byte offset accessed */
    } BYTE_ACCESS;


/* Memory global SCP support routines */

t_stat mem_examine (t_value *eval_array, t_addr address, UNIT *uptr, int32 switches);
t_stat mem_deposit (t_value value,       t_addr address, UNIT *uptr, int32 switches);


/* Global memory functions.

   mem_initialize   : allocate main memory
   mem_is_empty     : check for a non-zero value within a range of memory locations
   mem_fill         : set all memory locations to a specified value

   mem_read         : read a word from main memory
   mem_write        : write a word to main memory

   mem_init_byte    : initialize a memory byte access structure
   mem_set_byte     : set the access structure to a new byte offset
   mem_lookup_byte  : return a byte at a specified index in a table
   mem_read_byte    : read the next byte from memory
   mem_write_byte   : write the next byte to memory
   mem_modify_byte  : replace the last byte written to memory
   mem_post_byte    : post the word containing the last byte modified in place to memory
   mem_update_byte  : rewrite the word containing the last byte written to memory

   fmt_byte_operand : format a byte operand in memory into a character string
   fmt_bcd_operand  : format a BCD operand in memory into a character string
*/

extern t_bool mem_initialize (uint32 memory_size);
extern t_bool mem_is_empty   (uint32 starting_address);
extern void   mem_fill       (uint32 starting_address, HP_WORD fill_value);

extern t_bool mem_read  (DEVICE *dptr, ACCESS_CLASS classification, uint32 offset, HP_WORD *value);
extern t_bool mem_write (DEVICE *dptr, ACCESS_CLASS classification, uint32 offset, HP_WORD  value);

extern void   mem_init_byte   (BYTE_ACCESS *bap, ACCESS_CLASS class, HP_WORD *byte_offset, uint32 block_length);
extern void   mem_set_byte    (BYTE_ACCESS *bap);
extern uint8  mem_lookup_byte (BYTE_ACCESS *bap, uint8 index);
extern uint8  mem_read_byte   (BYTE_ACCESS *bap);
extern void   mem_write_byte  (BYTE_ACCESS *bap, uint8 byte);
extern void   mem_modify_byte (BYTE_ACCESS *bap, uint8 byte);
extern void   mem_post_byte   (BYTE_ACCESS *bap);
extern void   mem_update_byte (BYTE_ACCESS *bap);

extern char   *fmt_byte_operand            (uint32 byte_address, uint32 byte_count);
extern char   *fmt_translated_byte_operand (uint32 byte_address, uint32 byte_count, uint32 table_address);
extern char   *fmt_bcd_operand             (uint32 byte_address, uint32 digit_count);