Move libraries around

This commit is contained in:
InvisibleUp 2023-04-02 09:15:18 -07:00
parent 53d2e6953f
commit 2afb2906da
22 changed files with 3 additions and 1213 deletions

5
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "src/incbin"]
path = src/incbin
url = https://github.com/graphitemaster/incbin
[submodule "src/tomlc99"]
path = src/tomlc99
path = lib/tomlc99
url = https://github.com/cktan/tomlc99

View File

@ -1,42 +0,0 @@
EXENAME = sim
OSD_DOS = osd_dos.c
OSDFILES = osd_linux.c # $(OSD_DOS)
MAINFILES = sim.c
MUSASHIFILES = m68kcpu.c m68kdasm.c softfloat/softfloat.c
MUSASHIGENCFILES = m68kops.c
MUSASHIGENHFILES = m68kops.h
MUSASHIGENERATOR = m68kmake
# EXE = .exe
# EXEPATH = .\\
EXE =
EXEPATH = ./
.CFILES = $(MAINFILES) $(OSDFILES) $(MUSASHIFILES) $(MUSASHIGENCFILES)
.OFILES = $(.CFILES:%.c=%.o)
CC = gcc
WARNINGS = -Wall -Wextra -pedantic
CFLAGS = $(WARNINGS)
LFLAGS = $(WARNINGS)
TARGET = $(EXENAME)$(EXE)
DELETEFILES = $(MUSASHIGENCFILES) $(MUSASHIGENHFILES) $(.OFILES) $(TARGET) $(MUSASHIGENERATOR)$(EXE)
all: $(TARGET)
clean:
rm -f $(DELETEFILES)
$(TARGET): $(MUSASHIGENHFILES) $(.OFILES) Makefile
$(CC) -o $@ $(.OFILES) $(LFLAGS) -lm
$(MUSASHIGENCFILES) $(MUSASHIGENHFILES): $(MUSASHIGENERATOR)$(EXE)
$(EXEPATH)$(MUSASHIGENERATOR)$(EXE)
$(MUSASHIGENERATOR)$(EXE): $(MUSASHIGENERATOR).c
$(CC) -o $(MUSASHIGENERATOR)$(EXE) $(MUSASHIGENERATOR).c

View File

@ -1,290 +0,0 @@
EXAMPLE:
-------
As an example, I'll build an imaginary hardware platform.
The system is fairly simple, comprising a 68000, an input device, an output
device, a non-maskable-interrupt device, and an interrupt controller.
The input device receives input from the user and asserts its interrupt
request line until its value is read. Reading from the input device's
memory-mapped port will both clear its interrupt request and read an ASCII
representation (8 bits) of what the user entered.
The output device reads value when it is selected through its memory-mapped
port and outputs it to a display. The value it reads will be interpreted as
an ASCII value and output to the display. The output device is fairly slow
(it can only process 1 byte per second), and so it asserts its interrupt
request line when it is ready to receive a byte. Writing to the output device
sends a byte to it. If the output device is not ready, the write is ignored.
Reading from the output device returns 0 and clears its interrupt request line
until another byte is written to it and 1 second elapses.
The non-maskable-interrupt (NMI) device, as can be surmised from the name,
generates a non-maskable-interrupt. This is connected to some kind of external
switch that the user can push to generate a NMI.
Since there are 3 devices interrupting the CPU, an interrupt controller is
needed. The interrupt controller takes 7 inputs and encodes the highest
priority asserted line on the 3 output pins. the input device is wired to IN2
and the output device is wired to IN1 on the controller. The NMI device is
wired to IN7 and all the other inputs are wired low.
The bus is also connected to a 1K ROM and a 256 byte RAM.
Beware: This platform places ROM and RAM in the same address range and uses
the FC pins to select the correct address space!
(You didn't expect me to make it easy, did you? =)
Here is the schematic in all its ASCII splendour:
-------------------------------------------------
NMI TIED
SWITCH LOW
| |
| +-+-+-+
| | | | | +------------------------------------------------+
| | | | | | +------------------------------------+ |
| | | | | | | | |
+-------------+ | |
|7 6 5 4 3 2 1| | |
| | | |
| INT CONTRLR | | |
| | | |
|i i i | | |
|2 1 0 | | |
+-------------+ | |
| | | | |
| | | +--------------------------------+--+ | |
o o o | | | | |
+--------------+ +-------+ +----------+ +---------+ +----------+
| I I I a | | | | | | r a i | | i |
| 2 1 0 23 | | | | | | e c | | |
| | | | | | | a k | | |
| | | | | | | d | | |
| | | | | | | | | |
| M68000 | | ROM | | RAM | | IN | | OUT |
| | | | | | | | | |
| a9|--|a9 |--| |--| |--| |
| a8|--|a8 |--| |--| |--| |
| a7|--|a7 |--|a7 |--| |--| |
| a6|--|a6 |--|a6 |--| |--| |
| a5|--|a5 |--|a5 |--| |--| |
| a4|--|a4 |--|a4 |--| |--| |
| a3|--|a3 |--|a3 |--| |--| |
| a2|--|a2 |--|a2 |--| |--| |
| a1|--|a1 |--|a1 |--| |--| |
| a0|--|a0 |--|a0 |--| |--| |
| | | | | | | | | |
| d15|--|d15 |--|d15 |--| |--| |
| d14|--|d14 |--|d14 |--| |--| |
| d13|--|d13 |--|d13 |--| |--| |
| d12|--|d12 |--|d12 |--| |--| |
| d11|--|d11 |--|d11 |--| |--| |
| d10|--|d10 |--|d10 |--| |--| |
| d9|--|d9 |--|d9 |--| |--| |
| d8|--|d8 |--|d8 |--| |--| |
| d7|--|d7 |--|d7 |--|d7 |--|d7 |
| d6|--|d6 |--|d6 |--|d6 |--|d6 |
| d5|--|d5 |--|d5 |--|d5 |--|d5 |
| d4|--|d4 |--|d4 |--|d4 |--|d4 |
| d3|--|d3 |--|d3 |--|d3 |--|d3 |
| d2|--|d2 |--|d2 |--|d2 |--|d2 |
| d1|--|d1 |--|d1 |--|d1 |--|d1 w |
| d0|--|d0 |--|d0 |--|d0 |--|d0 r |
| | | | | | | | | i a |
| a F F F | | | | | | | | t c |
|22 rW 2 1 0 | | cs | | cs rW | | | | e k |
+--------------+ +-------+ +----------+ +---------+ +----------+
| | | | | | | | | |
| | | | | | | | | |
| | | | | +-------+ +-----+ | +---+ |
| | | | | | IC1 | | IC2 | | |AND| |
| | | | | |a b c d| |a b c| | +---+ |
| | | | | +-------+ +-----+ | | | |
| | | | | | | | | | | | | | +--+
| | | | | | | | | | | | | | |
| | | | | | | | | | | | | | |
| | | | | | | | | | | | | | |
| | | | +-----)-)-+-)----)-)-+ | | |
| | | +-------)-+---)----)-+ | | |
| | +---------+-----)----+ | | |
| | | | | |
| +------------------+-----------+----------------------+ |
| |
+-----------------------------------------------------------+
IC1: output=1 if a=0 and b=1 and c=0 and d=0
IC2: output=1 if a=0 and b=0 and c=1
Here is the listing for program.bin:
-----------------------------------
INPUT_ADDRESS equ $800000
OUTPUT_ADDRESS equ $400000
CIRCULAR_BUFFER equ $c0
CAN_OUTPUT equ $d0
STACK_AREA equ $100
vector_table:
00000000 0000 0100 dc.l STACK_AREA * 0: SP
00000004 0000 00c0 dc.l init * 1: PC
00000008 0000 0148 dc.l unhandled_exception * 2: bus error
0000000c 0000 0148 dc.l unhandled_exception * 3: address error
00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction
00000014 0000 0148 dc.l unhandled_exception * 5: zero divide
00000018 0000 0148 dc.l unhandled_exception * 6: chk
0000001c 0000 0148 dc.l unhandled_exception * 7: trapv
00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation
00000024 0000 0148 dc.l unhandled_exception * 9: trace
00000028 0000 0148 dc.l unhandled_exception * 10: 1010
0000002c 0000 0148 dc.l unhandled_exception * 11: 1111
00000030 0000 0148 dc.l unhandled_exception * 12: -
00000034 0000 0148 dc.l unhandled_exception * 13: -
00000038 0000 0148 dc.l unhandled_exception * 14: -
0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt
00000040 0000 0148 dc.l unhandled_exception * 16: -
00000044 0000 0148 dc.l unhandled_exception * 17: -
00000048 0000 0148 dc.l unhandled_exception * 18: -
0000004c 0000 0148 dc.l unhandled_exception * 19: -
00000050 0000 0148 dc.l unhandled_exception * 20: -
00000054 0000 0148 dc.l unhandled_exception * 21: -
00000058 0000 0148 dc.l unhandled_exception * 22: -
0000005c 0000 0148 dc.l unhandled_exception * 23: -
00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt
00000064 0000 0136 dc.l output_ready * 25: l1 irq
00000068 0000 010e dc.l input_ready * 26: l2 irq
0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq
00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq
00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq
00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq
0000007c 0000 014e dc.l nmi * 31: l7 irq
00000080 0000 0148 dc.l unhandled_exception * 32: trap 0
00000084 0000 0148 dc.l unhandled_exception * 33: trap 1
00000088 0000 0148 dc.l unhandled_exception * 34: trap 2
0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3
00000090 0000 0148 dc.l unhandled_exception * 36: trap 4
00000094 0000 0148 dc.l unhandled_exception * 37: trap 5
00000098 0000 0148 dc.l unhandled_exception * 38: trap 6
0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7
000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8
000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9
000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10
000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11
000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12
000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13
000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14
000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15
* This is the end of the useful part of the table.
* We will now do the Capcom thing and put code starting at $c0.
init:
* Copy the exception vector table to RAM.
000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index
000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors)
000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch
000000ce 2208 move.l a0, d1 * d1 is ROM index
000000d0 4481 neg.l d1
copy_table:
000000d2 22fb 18fe dc.l $22fb18fe * stoopid as68k generates 020 code here
* move.l (copy_table,PC,d1.l), (a1)+
000000d6 5841 addq #4, d1
000000d8 51c8 fff8 dbf d0, copy_table
main_init:
* Initialize main program
000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT
000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6
000000e6 7c00 moveq #0, d6 * output buffer ptr
000000e8 7e00 moveq #0, d7 * input buffer ptr
000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask
main:
* Main program
000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output?
000000f2 67fa beq main
000000f4 be06 cmp.b d6, d7 * is there data?
000000f6 67f6 beq main
000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT
000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data
0000
00000106 5246 addq #1, d6
00000108 0206 000f andi.b #15, d6 * update circular buffer
0000010c 60e0 bra main
input_ready:
0000010e 2f00 move.l d0, -(a7)
00000110 2f01 move.l d1, -(a7)
00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data
00000118 1007 move.b d7, d0 * check if buffer full
0000011a 5240 addq #1, d0
0000011c 0200 000f andi.b #15, d0
00000120 bc00 cmp.b d0, d6
00000122 6700 000c beq input_ready_quit * throw away if full
00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data
0000012a 5247 addq #1, d7
0000012c 0207 000f andi.b #15, d7 * update circular buffer
input_ready_quit:
00000130 221f move.l (a7)+, d1
00000132 201f move.l (a7)+, d0
00000134 4e73 rte
output_ready:
00000136 2f00 move.l d0, -(a7)
00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT
0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt
00000144 201f move.l (a7)+, d0
00000146 4e73 rte
unhandled_exception:
00000148 4e72 2700 stop #$2700 * wait for NMI
0000014c 60fa bra unhandled_exception * shouldn't get here
nmi:
* perform a soft reset
0000014e 46fc 2700 move #$2700, SR * set status register
00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer
00000156 4e70 reset * reset peripherals
00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter
END
Compiling the example host environment:
--------------------------------------
I've only put in an os-dependant portion for dos/windows, so you'll either
have to compile for that system or make your own osd code based on osd_dos.c
and modify the makefile accordingly.
I compiled this example using the compiler from mingw (www.mingw.org) but you
could also use djgpp (www.delorie.com).
- Copy the m68k files to a directory. Then extract the files from example.zip to
the same directory, overwriting m68kconf.h. program.bin is the actual 68000
program you will be running.
- Make your own osd_get_key() in the same fashion as in osd_dos.c if you're not
compiling for dos/windows.
- Type make
- Perform the necessary animal sacrifices.
- Type sim program.bin
Keys:
ESC - quits the simulator
~ - generates an NMI interrupt
Any other key - Genearate input for the input device
Note: I've cheated a bit in the emulation. There is no speed control
to set the speed the CPU runs at; it simply runs as fast as your
processor can run it.
To add speed control, you will need a high-precision timestamp
function (like the RDTSC instruction for newer Pentium CPUs)
and a bit of arithmetic to make the cycles argument for m68k_execute().
I'll leave that as an excercise to the reader.

View File

@ -1 +0,0 @@
../m68k.h

View File

@ -1 +0,0 @@
../m68k_in.c

View File

@ -1,220 +0,0 @@
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
/*
* MUSASHI
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright Karl Stenerud. All rights reserved.
*
* 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
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef M68KCONF__HEADER
#define M68KCONF__HEADER
/* Configuration switches.
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
* or macro you specify, rather than using callback functions whose pointer
* must be passed in using m68k_set_xxx_callback().
*/
#define OPT_OFF 0
#define OPT_ON 1
#define OPT_SPECIFY_HANDLER 2
/* ======================================================================== */
/* ============================== MAME STUFF ============================== */
/* ======================================================================== */
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
* to OPT_ON and use m68kmame.h to configure the 68k core.
*/
#ifndef M68K_COMPILE_FOR_MAME
#define M68K_COMPILE_FOR_MAME OPT_OFF
#endif /* M68K_COMPILE_FOR_MAME */
#if M68K_COMPILE_FOR_MAME == OPT_OFF
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ======================================================================== */
/* Turn ON if you want to use the following M68K variants */
#define M68K_EMULATE_010 OPT_ON
#define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON
#define M68K_EMULATE_040 OPT_ON
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
* and m68k_read_pcrelative_xx() for PC-relative addressing.
* If off, all read requests from the CPU will be redirected to m68k_read_xx()
*/
#define M68K_SEPARATE_READS OPT_OFF
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
* predecrement destination EA mode instead of m68k_write_32().
* To simulate real 68k behavior, m68k_write_32_pd() must first write the high
* word to [address+2], and then write the low word to [address].
*/
#define M68K_SIMULATE_PD_WRITES OPT_OFF
/* If ON, CPU will call the interrupt acknowledge callback when it services an
* interrupt.
* If off, all interrupts will be autovectored and all interrupt requests will
* auto-clear when the interrupt is serviced.
*/
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
#define M68K_INT_ACK_CALLBACK(A) cpu_irq_ack(A)
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
* a breakpoint instruction and it is running a 68010+.
*/
#define M68K_EMULATE_BKPT_ACK OPT_OFF
#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
/* If ON, the CPU will monitor the trace flags and take trace exceptions
*/
#define M68K_EMULATE_TRACE OPT_OFF
/* If ON, CPU will call the output reset callback when it encounters a reset
* instruction.
*/
#define M68K_EMULATE_RESET OPT_SPECIFY_HANDLER
#define M68K_RESET_CALLBACK() cpu_pulse_reset()
/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn
* instruction.
*/
#define M68K_CMPILD_HAS_CALLBACK OPT_OFF
#define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r)
/* If ON, CPU will call the callback when it encounters a rte
* instruction.
*/
#define M68K_RTE_HAS_CALLBACK OPT_OFF
#define M68K_RTE_CALLBACK() your_rte_handler_function()
/* If ON, CPU will call the callback when it encounters a tas
* instruction.
*/
#define M68K_TAS_HAS_CALLBACK OPT_OFF
#define M68K_TAS_CALLBACK() your_tas_handler_function()
/* If ON, CPU will call the callback when it encounters an illegal instruction
* passing the opcode as argument. If the callback returns 1, then it's considered
* as a normal instruction, and the illegal exception in canceled. If it returns 0,
* the exception occurs normally.
* The callback looks like int callback(int opcode)
* You should put OPT_SPECIFY_HANDLER here if you cant to use it, otherwise it will
* use a dummy default handler and you'll have to call m68k_set_illg_instr_callback explicitely
*/
#define M68K_ILLG_HAS_CALLBACK OPT_OFF
#define M68K_ILLG_CALLBACK(opcode) op_illg(opcode)
/* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real
* 68000 would. This should be enabled and the callback should be set if you
* want to properly emulate the m68010 or higher. (moves uses function codes
* to read/write data from different address spaces)
*/
#define M68K_EMULATE_FC OPT_SPECIFY_HANDLER
#define M68K_SET_FC_CALLBACK(A) cpu_set_fc(A)
/* If ON, CPU will call the pc changed callback when it changes the PC by a
* large value. This allows host programs to be nicer when it comes to
* fetching immediate data and instructions on a banked memory system.
*/
#define M68K_MONITOR_PC OPT_OFF
#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
/* If ON, CPU will call the instruction hook callback before every
* instruction.
*/
#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
#define M68K_INSTRUCTION_CALLBACK(pc) cpu_instr_callback(pc)
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
#define M68K_EMULATE_PREFETCH OPT_ON
/* If ON, the CPU will generate address error exceptions if it tries to
* access a word or longword at an odd address.
* NOTE: This is only emulated properly for 68000 mode.
*/
#define M68K_EMULATE_ADDRESS_ERROR OPT_ON
/* Turn ON to enable logging of illegal instruction calls.
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
* Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
*/
#define M68K_LOG_ENABLE OPT_OFF
#define M68K_LOG_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE some_file_handle
/* ----------------------------- COMPATIBILITY ---------------------------- */
/* The following options set optimizations that violate the current ANSI
* standard, but will be compliant under the forthcoming C9X standard.
*/
/* If ON, the enulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_ON
#include "sim.h"
#define m68k_read_memory_8(A) cpu_read_byte(A)
#define m68k_read_memory_16(A) cpu_read_word(A)
#define m68k_read_memory_32(A) cpu_read_long(A)
#define m68k_read_disassembler_16(A) cpu_read_word_dasm(A)
#define m68k_read_disassembler_32(A) cpu_read_long_dasm(A)
#define m68k_write_memory_8(A, V) cpu_write_byte(A, V)
#define m68k_write_memory_16(A, V) cpu_write_word(A, V)
#define m68k_write_memory_32(A, V) cpu_write_long(A, V)
#endif /* M68K_COMPILE_FOR_MAME */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#endif /* M68KCONF__HEADER */

View File

@ -1 +0,0 @@
../m68kcpu.c

View File

@ -1 +0,0 @@
../m68kcpu.h

View File

@ -1 +0,0 @@
../m68kdasm.c

View File

@ -1 +0,0 @@
../m68kfpu.c

View File

@ -1 +0,0 @@
../m68kmake.c

View File

@ -1 +0,0 @@
../m68kmmu.h

View File

@ -1,6 +0,0 @@
#ifndef HEADER__OSD
#define HEADER__OSD
int osd_get_char(void);
#endif /* HEADER__OSD */

View File

@ -1,16 +0,0 @@
#include "osd.h"
/* OS-dependant code to get a character from the user.
* This function must not block, and must either return an ASCII code or -1.
*/
#include <conio.h>
int osd_get_char(void)
{
int ch = -1;
if(kbhit())
{
while(kbhit())
ch = getch();
}
return ch;
}

View File

@ -1,46 +0,0 @@
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
void changemode(int dir)
{
static struct termios oldt, newt;
if ( dir == 1 )
{
tcgetattr( STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
}
else
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
int kbhit (void)
{
struct timeval tv;
fd_set rdfs;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rdfs);
FD_SET (STDIN_FILENO, &rdfs);
select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &rdfs);
}
int osd_get_char() {
changemode(1);
int ch = -1;
while(kbhit())
ch = getchar();
changemode(0);
return ch;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 B

View File

@ -1,563 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include "sim.h"
#include "m68k.h"
#include "osd.h"
void disassemble_program();
/* Memory-mapped IO ports */
#define INPUT_ADDRESS 0x800000
#define OUTPUT_ADDRESS 0x400000
/* IRQ connections */
#define IRQ_NMI_DEVICE 7
#define IRQ_INPUT_DEVICE 2
#define IRQ_OUTPUT_DEVICE 1
/* Time between characters sent to output device (seconds) */
#define OUTPUT_DEVICE_PERIOD 1
/* ROM and RAM sizes */
#define MAX_ROM 0xfff
#define MAX_RAM 0xff
/* Read/write macros */
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \
(BASE)[(ADDR)+1])
#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) | \
((BASE)[(ADDR)+1]<<16) | \
((BASE)[(ADDR)+2]<<8) | \
(BASE)[(ADDR)+3])
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)&0xff
#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff; \
(BASE)[(ADDR)+1] = (VAL)&0xff
#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff; \
(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff; \
(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff; \
(BASE)[(ADDR)+3] = (VAL)&0xff
/* Prototypes */
void exit_error(char* fmt, ...);
unsigned int cpu_read_byte(unsigned int address);
unsigned int cpu_read_word(unsigned int address);
unsigned int cpu_read_long(unsigned int address);
void cpu_write_byte(unsigned int address, unsigned int value);
void cpu_write_word(unsigned int address, unsigned int value);
void cpu_write_long(unsigned int address, unsigned int value);
void cpu_pulse_reset(void);
void cpu_set_fc(unsigned int fc);
int cpu_irq_ack(int level);
void nmi_device_reset(void);
void nmi_device_update(void);
int nmi_device_ack(void);
void input_device_reset(void);
void input_device_update(void);
int input_device_ack(void);
unsigned int input_device_read(void);
void input_device_write(unsigned int value);
void output_device_reset(void);
void output_device_update(void);
int output_device_ack(void);
unsigned int output_device_read(void);
void output_device_write(unsigned int value);
void int_controller_set(unsigned int value);
void int_controller_clear(unsigned int value);
void get_user_input(void);
/* Data */
unsigned int g_quit = 0; /* 1 if we want to quit */
unsigned int g_nmi = 0; /* 1 if nmi pending */
int g_input_device_value = -1; /* Current value in input device */
unsigned int g_output_device_ready = 0; /* 1 if output device is ready */
time_t g_output_device_last_output; /* Time of last char output */
unsigned int g_int_controller_pending = 0; /* list of pending interrupts */
unsigned int g_int_controller_highest_int = 0; /* Highest pending interrupt */
unsigned char g_rom[MAX_ROM+1]; /* ROM */
unsigned char g_ram[MAX_RAM+1]; /* RAM */
unsigned int g_fc; /* Current function code from CPU */
/* Exit with an error message. Use printf syntax. */
void exit_error(char* fmt, ...)
{
static int guard_val = 0;
char buff[100];
unsigned int pc;
va_list args;
if(guard_val)
return;
else
guard_val = 1;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
pc = m68k_get_reg(NULL, M68K_REG_PPC);
m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
fprintf(stderr, "At %04x: %s\n", pc, buff);
exit(EXIT_FAILURE);
}
/* Read data from RAM, ROM, or a device */
unsigned int cpu_read_byte(unsigned int address)
{
if(g_fc & 2) /* Program */
{
if(address > MAX_ROM)
exit_error("Attempted to read byte from ROM address %08x", address);
return READ_BYTE(g_rom, address);
}
/* Otherwise it's data space */
switch(address)
{
case INPUT_ADDRESS:
return input_device_read();
case OUTPUT_ADDRESS:
return output_device_read();
default:
break;
}
if(address > MAX_RAM)
exit_error("Attempted to read byte from RAM address %08x", address);
return READ_BYTE(g_ram, address);
}
unsigned int cpu_read_word(unsigned int address)
{
if(g_fc & 2) /* Program */
{
if(address > MAX_ROM)
exit_error("Attempted to read word from ROM address %08x", address);
return READ_WORD(g_rom, address);
}
/* Otherwise it's data space */
switch(address)
{
case INPUT_ADDRESS:
return input_device_read();
case OUTPUT_ADDRESS:
return output_device_read();
default:
break;
}
if(address > MAX_RAM)
exit_error("Attempted to read word from RAM address %08x", address);
return READ_WORD(g_ram, address);
}
unsigned int cpu_read_long(unsigned int address)
{
if(g_fc & 2) /* Program */
{
if(address > MAX_ROM)
exit_error("Attempted to read long from ROM address %08x", address);
return READ_LONG(g_rom, address);
}
/* Otherwise it's data space */
switch(address)
{
case INPUT_ADDRESS:
return input_device_read();
case OUTPUT_ADDRESS:
return output_device_read();
default:
break;
}
if(address > MAX_RAM)
exit_error("Attempted to read long from RAM address %08x", address);
return READ_LONG(g_ram, address);
}
unsigned int cpu_read_word_dasm(unsigned int address)
{
if(address > MAX_ROM)
exit_error("Disassembler attempted to read word from ROM address %08x", address);
return READ_WORD(g_rom, address);
}
unsigned int cpu_read_long_dasm(unsigned int address)
{
if(address > MAX_ROM)
exit_error("Dasm attempted to read long from ROM address %08x", address);
return READ_LONG(g_rom, address);
}
/* Write data to RAM or a device */
void cpu_write_byte(unsigned int address, unsigned int value)
{
if(g_fc & 2) /* Program */
exit_error("Attempted to write %02x to ROM address %08x", value&0xff, address);
/* Otherwise it's data space */
switch(address)
{
case INPUT_ADDRESS:
input_device_write(value&0xff);
return;
case OUTPUT_ADDRESS:
output_device_write(value&0xff);
return;
default:
break;
}
if(address > MAX_RAM)
exit_error("Attempted to write %02x to RAM address %08x", value&0xff, address);
WRITE_BYTE(g_ram, address, value);
}
void cpu_write_word(unsigned int address, unsigned int value)
{
if(g_fc & 2) /* Program */
exit_error("Attempted to write %04x to ROM address %08x", value&0xffff, address);
/* Otherwise it's data space */
switch(address)
{
case INPUT_ADDRESS:
input_device_write(value&0xffff);
return;
case OUTPUT_ADDRESS:
output_device_write(value&0xffff);
return;
default:
break;
}
if(address > MAX_RAM)
exit_error("Attempted to write %04x to RAM address %08x", value&0xffff, address);
WRITE_WORD(g_ram, address, value);
}
void cpu_write_long(unsigned int address, unsigned int value)
{
if(g_fc & 2) /* Program */
exit_error("Attempted to write %08x to ROM address %08x", value, address);
/* Otherwise it's data space */
switch(address)
{
case INPUT_ADDRESS:
input_device_write(value);
return;
case OUTPUT_ADDRESS:
output_device_write(value);
return;
default:
break;
}
if(address > MAX_RAM)
exit_error("Attempted to write %08x to RAM address %08x", value, address);
WRITE_LONG(g_ram, address, value);
}
/* Called when the CPU pulses the RESET line */
void cpu_pulse_reset(void)
{
nmi_device_reset();
output_device_reset();
input_device_reset();
}
/* Called when the CPU changes the function code pins */
void cpu_set_fc(unsigned int fc)
{
g_fc = fc;
}
/* Called when the CPU acknowledges an interrupt */
int cpu_irq_ack(int level)
{
switch(level)
{
case IRQ_NMI_DEVICE:
return nmi_device_ack();
case IRQ_INPUT_DEVICE:
return input_device_ack();
case IRQ_OUTPUT_DEVICE:
return output_device_ack();
}
return M68K_INT_ACK_SPURIOUS;
}
/* Implementation for the NMI device */
void nmi_device_reset(void)
{
g_nmi = 0;
}
void nmi_device_update(void)
{
if(g_nmi)
{
g_nmi = 0;
int_controller_set(IRQ_NMI_DEVICE);
}
}
int nmi_device_ack(void)
{
printf("\nNMI\n");fflush(stdout);
int_controller_clear(IRQ_NMI_DEVICE);
return M68K_INT_ACK_AUTOVECTOR;
}
/* Implementation for the input device */
void input_device_reset(void)
{
g_input_device_value = -1;
int_controller_clear(IRQ_INPUT_DEVICE);
}
void input_device_update(void)
{
if(g_input_device_value >= 0)
int_controller_set(IRQ_INPUT_DEVICE);
}
int input_device_ack(void)
{
return M68K_INT_ACK_AUTOVECTOR;
}
unsigned int input_device_read(void)
{
int value = g_input_device_value > 0 ? g_input_device_value : 0;
int_controller_clear(IRQ_INPUT_DEVICE);
g_input_device_value = -1;
return value;
}
void input_device_write(unsigned int value)
{
(void)value;
}
/* Implementation for the output device */
void output_device_reset(void)
{
g_output_device_last_output = time(NULL);
g_output_device_ready = 0;
int_controller_clear(IRQ_OUTPUT_DEVICE);
}
void output_device_update(void)
{
if(!g_output_device_ready)
{
if((time(NULL) - g_output_device_last_output) >= OUTPUT_DEVICE_PERIOD)
{
g_output_device_ready = 1;
int_controller_set(IRQ_OUTPUT_DEVICE);
}
}
}
int output_device_ack(void)
{
return M68K_INT_ACK_AUTOVECTOR;
}
unsigned int output_device_read(void)
{
int_controller_clear(IRQ_OUTPUT_DEVICE);
return 0;
}
void output_device_write(unsigned int value)
{
char ch;
if(g_output_device_ready)
{
ch = value & 0xff;
printf("%c", ch);
g_output_device_last_output = time(NULL);
g_output_device_ready = 0;
int_controller_clear(IRQ_OUTPUT_DEVICE);
}
}
/* Implementation for the interrupt controller */
void int_controller_set(unsigned int value)
{
unsigned int old_pending = g_int_controller_pending;
g_int_controller_pending |= (1<<value);
if(old_pending != g_int_controller_pending && value > g_int_controller_highest_int)
{
g_int_controller_highest_int = value;
m68k_set_irq(g_int_controller_highest_int);
}
}
void int_controller_clear(unsigned int value)
{
g_int_controller_pending &= ~(1<<value);
for(g_int_controller_highest_int = 7;g_int_controller_highest_int > 0;g_int_controller_highest_int--)
if(g_int_controller_pending & (1<<g_int_controller_highest_int))
break;
m68k_set_irq(g_int_controller_highest_int);
}
/* Parse user input and update any devices that need user input */
void get_user_input(void)
{
static int last_ch = -1;
int ch = osd_get_char();
if(ch >= 0)
{
switch(ch)
{
case 0x1b:
g_quit = 1;
break;
case '~':
if(last_ch != ch)
g_nmi = 1;
break;
default:
g_input_device_value = ch;
}
}
last_ch = ch;
}
/* Disassembler */
void make_hex(char* buff, unsigned int pc, unsigned int length)
{
char* ptr = buff;
for(;length>0;length -= 2)
{
sprintf(ptr, "%04x", cpu_read_word_dasm(pc));
pc += 2;
ptr += 4;
if(length > 2)
*ptr++ = ' ';
}
}
void disassemble_program()
{
unsigned int pc;
unsigned int instr_size;
char buff[100];
char buff2[100];
pc = cpu_read_long_dasm(4);
while(pc <= 0x16e)
{
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
make_hex(buff2, pc, instr_size);
printf("%03x: %-20s: %s\n", pc, buff2, buff);
pc += instr_size;
}
fflush(stdout);
}
void cpu_instr_callback(int pc)
{
(void)pc;
/* The following code would print out instructions as they are executed */
/*
static char buff[100];
static char buff2[100];
static unsigned int pc;
static unsigned int instr_size;
pc = m68k_get_reg(NULL, M68K_REG_PC);
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
make_hex(buff2, pc, instr_size);
printf("E %03x: %-20s: %s\n", pc, buff2, buff);
fflush(stdout);
*/
}
/* The main loop */
int main(int argc, char* argv[])
{
FILE* fhandle;
if(argc != 2)
{
printf("Usage: sim <program file>\n");
exit(-1);
}
if((fhandle = fopen(argv[1], "rb")) == NULL)
exit_error("Unable to open %s", argv[1]);
if(fread(g_rom, 1, MAX_ROM+1, fhandle) <= 0)
exit_error("Error reading %s", argv[1]);
// disassemble_program();
m68k_init();
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_pulse_reset();
input_device_reset();
output_device_reset();
nmi_device_reset();
g_quit = 0;
while(!g_quit)
{
// Our loop requires some interleaving to allow us to update the
// input, output, and nmi devices.
get_user_input();
// Values to execute determine the interleave rate.
// Smaller values allow for more accurate interleaving with multiple
// devices/CPUs but is more processor intensive.
// 100000 is usually a good value to start at, then work from there.
// Note that I am not emulating the correct clock speed!
m68k_execute(100000);
output_device_update();
input_device_update();
nmi_device_update();
}
return 0;
}

View File

@ -1,15 +0,0 @@
#ifndef SIM__HEADER
#define SIM__HEADER
unsigned int cpu_read_byte(unsigned int address);
unsigned int cpu_read_word(unsigned int address);
unsigned int cpu_read_long(unsigned int address);
void cpu_write_byte(unsigned int address, unsigned int value);
void cpu_write_word(unsigned int address, unsigned int value);
void cpu_write_long(unsigned int address, unsigned int value);
void cpu_pulse_reset(void);
void cpu_set_fc(unsigned int fc);
int cpu_irq_ack(int level);
void cpu_instr_callback(int pc);
#endif /* SIM__HEADER */

View File

@ -167,7 +167,7 @@ EMU_SRC = [
'src/GLOBGLUE.c',
'src/CFGMAN.c',
'src/LANG/INTLCHAR.c',
'src/tomlc99/toml.c'
'lib/tomlc99/toml.c'
]
EMU_INC = include_directories([

View File

@ -5,7 +5,7 @@
*
*/
#include "tomlc99/toml.h"
#include "lib/tomlc99/toml.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

@ -1 +0,0 @@
Subproject commit c9f3f0091948af39e187559100d0c6c5f2f68ebc