ack/plat/linux68k/emu/musashi/example/example.txt
tevorbl 799900f45a update platform linux68k
latest version of musashi engine
includes floating point emulation
(plus a few patches to add in missing opcodes needed by ack - see tags JFF & TBB)

added a few missing linux syscalls in sim.c

pascal now runs pretty well
quick test with modula2 passes

c gets the floating point numbers wrong, so more work needed here

other languages untested

plat/linux68k/emu/build.lua is probably not quite right - the softfloat directory is compiled in the wrong place
2020-05-28 13:06:08 +01:00

291 lines
15 KiB
Plaintext
Executable file

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.