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

   Copyright (c) 2016-2022, 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.

   23-Nov-22    JDB     Added "mem_copy_loader" declaration
   26-Oct-21    JDB     Changed debug flags to private trace flags
   07-Apr-21    JDB     Added mem_bank_mask declaration
   25-Sep-20    JDB     Added initial_word_address and mem_reset_byte declarations
   23-Sep-20    JDB     Changed uint8 uses to HP_BYTE
   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.
*/



/* CPU, memory, and I/O private tracing flags.

   Private flags are allocated in descending order to avoid conflicts
   with global flags that are allocated in ascending order.
*/

#define TRACE_INSTR         (1u << 30)          /* trace instruction executions */
#define TRACE_DATA          (1u << 29)          /* trace memory data accesses */
#define TRACE_FETCH         (1u << 28)          /* trace memory instruction fetches */
#define TRACE_REG           (1u << 27)          /* trace register values */
#define TRACE_OPND          (1u << 26)          /* trace instruction operands */
#define TRACE_EXEC          (1u << 25)          /* trace matching instruction execution states */
#define TRACE_DIO           (1u << 24)          /* trace direct I/O commands */
#define TRACE_PIO           (1u << 23)          /* trace programmed I/O commands */
#define TRACE_IRQ           (1u << 22)          /* trace interrupt requests */
#define TRACE_SR            (1u << 21)          /* trace service requests */


/* 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        initial_word_address;                 /*   initial word address containing the first byte */
    uint32        initial_byte_offset;                  /*   initial relative byte offset */
    uint32        length;                               /*   (trace) length of the block of bytes accessed */
    uint32        initial_byte_address;                 /*   (trace) initial absolute byte address */
    uint32        first_byte_address;                   /*   (trace) lowest absolute byte address accessed */
    uint32        first_byte_offset;                    /*   (trace) lowest relative byte offset accessed */
    } BYTE_ACCESS;


/* Memory global state */

extern uint32 mem_bank_mask;                    /* the mask for the memory bank register size */


/* Memory global SCP support routines */

extern t_stat mem_examine (t_value *eval_array, t_addr address, UNIT *uptr, int32 switches);
extern 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_reset_byte   : reset to the start of the byte access
   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 void   mem_copy_loader (uint32 starting_address, const MEMORY_WORD *buffer, size_t buffer_size);

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 void    mem_reset_byte  (BYTE_ACCESS *bap);
extern HP_BYTE mem_lookup_byte (BYTE_ACCESS *bap, uint8 index);
extern HP_BYTE mem_read_byte   (BYTE_ACCESS *bap);
extern void    mem_write_byte  (BYTE_ACCESS *bap, HP_BYTE byte);
extern void    mem_modify_byte (BYTE_ACCESS *bap, HP_BYTE 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);
