src/musashi/example/example.txt

Sat, 19 Apr 2014 02:19:39 -0600

author
andrew@localhost
date
Sat, 19 Apr 2014 02:19:39 -0600
changeset 152
d61e13d6e2a5
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

fixed timing on OSes that set a minimum time for sleeps (previously the main loop code assumed no minimum sleep time; the new version uses longer sleeps less frequently)

philpem@0 1 EXAMPLE:
philpem@0 2 -------
philpem@0 3 As an example, I'll build an imaginary hardware platform.
philpem@0 4
philpem@0 5
philpem@0 6 The system is fairly simple, comprising of a 000, an input device, an output
philpem@0 7 device, a non-maskable-interrupt device, and an interrupt controller.
philpem@0 8
philpem@0 9
philpem@0 10 The input device receives input from the user and asserts its interrupt
philpem@0 11 request line until its value is read. Reading from the input device's
philpem@0 12 memory-mapped port will both clear its interrupt request and read an ASCII
philpem@0 13 representation (8 bits) of what the user entered.
philpem@0 14
philpem@0 15 The output device reads value when it is selected through its memory-mapped
philpem@0 16 port and outputs it to a display. The value it reads will be interpreted as
philpem@0 17 an ASCII value and output to the display. The output device is fairly slow
philpem@0 18 (it can only process 1 byte per second), and so it asserts its interrupt
philpem@0 19 request line when it is ready to receive a byte. Writing to the output device
philpem@0 20 sends a byte to it. If the output device is not ready, the write is ignored.
philpem@0 21 Reading from the output device returns 0 and clears its interrupt request line
philpem@0 22 until another byte is written to it and 1 second elapses.
philpem@0 23
philpem@0 24 The non-maskable-interrupt (NMI) device, as can be surmised from the name,
philpem@0 25 generates a non-maskable-interrupt. This is connected to some kind of external
philpem@0 26 switch that the user can push to generate a NMI.
philpem@0 27
philpem@0 28 Since there are 3 devices interrupting the CPU, an interrupt controller is
philpem@0 29 needed. The interrupt controller takes 7 inputs and encodes the highest
philpem@0 30 priority asserted line on the 3 output pins. the input device is wired to IN2
philpem@0 31 and the output device is wired to IN1 on the controller. The NMI device is
philpem@0 32 wired to IN7 and all the other inputs are wired low.
philpem@0 33
philpem@0 34 The bus is also connected to a 1K ROM and a 256 byte RAM.
philpem@0 35 Beware: This platform places ROM and RAM in the same address range and uses
philpem@0 36 the FC pins to select the correct address space!
philpem@0 37 (You didn't expect me to make it easy, did you? =)
philpem@0 38
philpem@0 39 There are two ways to handle address spaces with Musashi:
philpem@0 40
philpem@0 41 1. Enable M68K_SEPARATE_READS and make handler functions for immediate and
philpem@0 42 pc-relative reads.
philpem@0 43
philpem@0 44 2. Enable M68K_EMULATE_FC and make a callback function for function code
philpem@0 45 changes.
philpem@0 46
philpem@0 47 Both methods will work in this case, but I've opted for the "more correct"
philpem@0 48 function code pin emulation for this example.
philpem@0 49
philpem@0 50
philpem@0 51
philpem@0 52 Here is the schematic in all its ASCII splendour:
philpem@0 53 -------------------------------------------------
philpem@0 54
philpem@0 55 NMI TIED
philpem@0 56 SWITCH LOW
philpem@0 57 | |
philpem@0 58 | +-+-+-+
philpem@0 59 | | | | | +------------------------------------------------+
philpem@0 60 | | | | | | +------------------------------------+ |
philpem@0 61 | | | | | | | | |
philpem@0 62 +-------------+ | |
philpem@0 63 |7 6 5 4 3 2 1| | |
philpem@0 64 | | | |
philpem@0 65 | INT CONTRLR | | |
philpem@0 66 | | | |
philpem@0 67 |i i i | | |
philpem@0 68 |2 1 0 | | |
philpem@0 69 +-------------+ | |
philpem@0 70 | | | | |
philpem@0 71 | | | +--------------------------------+--+ | |
philpem@0 72 o o o | | | | |
philpem@0 73 +--------------+ +-------+ +----------+ +---------+ +----------+
philpem@0 74 | I I I a | | | | | | r a i | | i |
philpem@0 75 | 2 1 0 23 | | | | | | e c | | |
philpem@0 76 | | | | | | | a k | | |
philpem@0 77 | | | | | | | d | | |
philpem@0 78 | | | | | | | | | |
philpem@0 79 | M68000 | | ROM | | RAM | | IN | | OUT |
philpem@0 80 | | | | | | | | | |
philpem@0 81 | a9|--|a9 |--| |--| |--| |
philpem@0 82 | a8|--|a8 |--| |--| |--| |
philpem@0 83 | a7|--|a7 |--|a7 |--| |--| |
philpem@0 84 | a6|--|a6 |--|a6 |--| |--| |
philpem@0 85 | a5|--|a5 |--|a5 |--| |--| |
philpem@0 86 | a4|--|a4 |--|a4 |--| |--| |
philpem@0 87 | a3|--|a3 |--|a3 |--| |--| |
philpem@0 88 | a2|--|a2 |--|a2 |--| |--| |
philpem@0 89 | a1|--|a1 |--|a1 |--| |--| |
philpem@0 90 | a0|--|a0 |--|a0 |--| |--| |
philpem@0 91 | | | | | | | | | |
philpem@0 92 | d15|--|d15 |--|d15 |--| |--| |
philpem@0 93 | d14|--|d14 |--|d14 |--| |--| |
philpem@0 94 | d13|--|d13 |--|d13 |--| |--| |
philpem@0 95 | d12|--|d12 |--|d12 |--| |--| |
philpem@0 96 | d11|--|d11 |--|d11 |--| |--| |
philpem@0 97 | d10|--|d10 |--|d10 |--| |--| |
philpem@0 98 | d9|--|d9 |--|d9 |--| |--| |
philpem@0 99 | d8|--|d8 |--|d8 |--| |--| |
philpem@0 100 | d7|--|d7 |--|d7 |--|d7 |--|d7 |
philpem@0 101 | d6|--|d6 |--|d6 |--|d6 |--|d6 |
philpem@0 102 | d5|--|d5 |--|d5 |--|d5 |--|d5 |
philpem@0 103 | d4|--|d4 |--|d4 |--|d4 |--|d4 |
philpem@0 104 | d3|--|d3 |--|d3 |--|d3 |--|d3 |
philpem@0 105 | d2|--|d2 |--|d2 |--|d2 |--|d2 |
philpem@0 106 | d1|--|d1 |--|d1 |--|d1 |--|d1 w |
philpem@0 107 | d0|--|d0 |--|d0 |--|d0 |--|d0 r |
philpem@0 108 | | | | | | | | | i a |
philpem@0 109 | a F F F | | | | | | | | t c |
philpem@0 110 |22 rW 2 1 0 | | cs | | cs rW | | | | e k |
philpem@0 111 +--------------+ +-------+ +----------+ +---------+ +----------+
philpem@0 112 | | | | | | | | | |
philpem@0 113 | | | | | | | | | |
philpem@0 114 | | | | | +-------+ +-----+ | +---+ |
philpem@0 115 | | | | | | IC1 | | IC2 | | |AND| |
philpem@0 116 | | | | | |a b c d| |a b c| | +---+ |
philpem@0 117 | | | | | +-------+ +-----+ | | | |
philpem@0 118 | | | | | | | | | | | | | | +--+
philpem@0 119 | | | | | | | | | | | | | | |
philpem@0 120 | | | | | | | | | | | | | | |
philpem@0 121 | | | | | | | | | | | | | | |
philpem@0 122 | | | | +-----)-)-+-)----)-)-+ | | |
philpem@0 123 | | | +-------)-+---)----)-+ | | |
philpem@0 124 | | +---------+-----)----+ | | |
philpem@0 125 | | | | | |
philpem@0 126 | +------------------+-----------+----------------------+ |
philpem@0 127 | |
philpem@0 128 +-----------------------------------------------------------+
philpem@0 129
philpem@0 130 IC1: output=1 if a=0 and b=1 and c=0 and d=0
philpem@0 131 IC2: output=1 if a=0 and b=0 and c=1
philpem@0 132
philpem@0 133
philpem@0 134
philpem@0 135 Here is the listing for program.bin:
philpem@0 136 -----------------------------------
philpem@0 137
philpem@0 138 INPUT_ADDRESS equ $800000
philpem@0 139 OUTPUT_ADDRESS equ $400000
philpem@0 140 CIRCULAR_BUFFER equ $c0
philpem@0 141 CAN_OUTPUT equ $d0
philpem@0 142 STACK_AREA equ $100
philpem@0 143
philpem@0 144 vector_table:
philpem@0 145 00000000 0000 0100 dc.l STACK_AREA * 0: SP
philpem@0 146 00000004 0000 00c0 dc.l init * 1: PC
philpem@0 147 00000008 0000 0148 dc.l unhandled_exception * 2: bus error
philpem@0 148 0000000c 0000 0148 dc.l unhandled_exception * 3: address error
philpem@0 149 00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction
philpem@0 150 00000014 0000 0148 dc.l unhandled_exception * 5: zero divide
philpem@0 151 00000018 0000 0148 dc.l unhandled_exception * 6: chk
philpem@0 152 0000001c 0000 0148 dc.l unhandled_exception * 7: trapv
philpem@0 153 00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation
philpem@0 154 00000024 0000 0148 dc.l unhandled_exception * 9: trace
philpem@0 155 00000028 0000 0148 dc.l unhandled_exception * 10: 1010
philpem@0 156 0000002c 0000 0148 dc.l unhandled_exception * 11: 1111
philpem@0 157 00000030 0000 0148 dc.l unhandled_exception * 12: -
philpem@0 158 00000034 0000 0148 dc.l unhandled_exception * 13: -
philpem@0 159 00000038 0000 0148 dc.l unhandled_exception * 14: -
philpem@0 160 0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt
philpem@0 161 00000040 0000 0148 dc.l unhandled_exception * 16: -
philpem@0 162 00000044 0000 0148 dc.l unhandled_exception * 17: -
philpem@0 163 00000048 0000 0148 dc.l unhandled_exception * 18: -
philpem@0 164 0000004c 0000 0148 dc.l unhandled_exception * 19: -
philpem@0 165 00000050 0000 0148 dc.l unhandled_exception * 20: -
philpem@0 166 00000054 0000 0148 dc.l unhandled_exception * 21: -
philpem@0 167 00000058 0000 0148 dc.l unhandled_exception * 22: -
philpem@0 168 0000005c 0000 0148 dc.l unhandled_exception * 23: -
philpem@0 169 00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt
philpem@0 170 00000064 0000 0136 dc.l output_ready * 25: l1 irq
philpem@0 171 00000068 0000 010e dc.l input_ready * 26: l2 irq
philpem@0 172 0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq
philpem@0 173 00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq
philpem@0 174 00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq
philpem@0 175 00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq
philpem@0 176 0000007c 0000 014e dc.l nmi * 31: l7 irq
philpem@0 177 00000080 0000 0148 dc.l unhandled_exception * 32: trap 0
philpem@0 178 00000084 0000 0148 dc.l unhandled_exception * 33: trap 1
philpem@0 179 00000088 0000 0148 dc.l unhandled_exception * 34: trap 2
philpem@0 180 0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3
philpem@0 181 00000090 0000 0148 dc.l unhandled_exception * 36: trap 4
philpem@0 182 00000094 0000 0148 dc.l unhandled_exception * 37: trap 5
philpem@0 183 00000098 0000 0148 dc.l unhandled_exception * 38: trap 6
philpem@0 184 0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7
philpem@0 185 000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8
philpem@0 186 000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9
philpem@0 187 000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10
philpem@0 188 000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11
philpem@0 189 000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12
philpem@0 190 000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13
philpem@0 191 000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14
philpem@0 192 000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15
philpem@0 193 * This is the end of the useful part of the table.
philpem@0 194 * We will now do the Capcom thing and put code starting at $c0.
philpem@0 195
philpem@0 196 init:
philpem@0 197 * Copy the exception vector table to RAM.
philpem@0 198 000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index
philpem@0 199 000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors)
philpem@0 200 000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch
philpem@0 201 000000ce 2208 move.l a0, d1 * d1 is ROM index
philpem@0 202 000000d0 4481 neg.l d1
philpem@0 203 copy_table:
philpem@0 204 000000d2 22fb 18fe dc.l $22fb18fe * #%#$ as68k generates 020 code here
philpem@0 205 * move.l (copy_table,PC,d1.l), (a1)+
philpem@0 206 000000d6 5841 addq #4, d1
philpem@0 207 000000d8 51c8 fff8 dbf d0, copy_table
philpem@0 208
philpem@0 209 main_init:
philpem@0 210 * Initialize main program
philpem@0 211 000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT
philpem@0 212 000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6
philpem@0 213 000000e6 7c00 moveq #0, d6 * output buffer ptr
philpem@0 214 000000e8 7e00 moveq #0, d7 * input buffer ptr
philpem@0 215 000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask
philpem@0 216 main:
philpem@0 217 * Main program
philpem@0 218 000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output?
philpem@0 219 000000f2 67fa beq main
philpem@0 220 000000f4 be06 cmp.b d6, d7 * is there data?
philpem@0 221 000000f6 67f6 beq main
philpem@0 222 000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT
philpem@0 223 000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data
philpem@0 224 0000
philpem@0 225 00000106 5246 addq #1, d6
philpem@0 226 00000108 0206 000f andi.b #15, d6 * update circular buffer
philpem@0 227 0000010c 60e0 bra main
philpem@0 228
philpem@0 229
philpem@0 230 input_ready:
philpem@0 231 0000010e 2f00 move.l d0, -(a7)
philpem@0 232 00000110 2f01 move.l d1, -(a7)
philpem@0 233 00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data
philpem@0 234 00000118 1007 move.b d7, d0 * check if buffer full
philpem@0 235 0000011a 5240 addq #1, d0
philpem@0 236 0000011c 0200 000f andi.b #15, d0
philpem@0 237 00000120 bc00 cmp.b d0, d6
philpem@0 238 00000122 6700 000c beq input_ready_quit * throw away if full
philpem@0 239 00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data
philpem@0 240 0000012a 5247 addq #1, d7
philpem@0 241 0000012c 0207 000f andi.b #15, d7 * update circular buffer
philpem@0 242 input_ready_quit:
philpem@0 243 00000130 221f move.l (a7)+, d1
philpem@0 244 00000132 201f move.l (a7)+, d0
philpem@0 245 00000134 4e73 rte
philpem@0 246
philpem@0 247 output_ready:
philpem@0 248 00000136 2f00 move.l d0, -(a7)
philpem@0 249 00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT
philpem@0 250 0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt
philpem@0 251 00000144 201f move.l (a7)+, d0
philpem@0 252 00000146 4e73 rte
philpem@0 253
philpem@0 254 unhandled_exception:
philpem@0 255 00000148 4e72 2700 stop #$2700 * wait for NMI
philpem@0 256 0000014c 60fa bra unhandled_exception * shouldn't get here
philpem@0 257
philpem@0 258 nmi:
philpem@0 259 * perform a soft reset
philpem@0 260 0000014e 46fc 2700 move #$2700, SR * set status register
philpem@0 261 00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer
philpem@0 262 00000156 4e70 reset * reset peripherals
philpem@0 263 00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter
philpem@0 264
philpem@0 265 END
philpem@0 266
philpem@0 267
philpem@0 268
philpem@0 269 Compiling the example host environment:
philpem@0 270 --------------------------------------
philpem@0 271
philpem@0 272 The following assumes that you are using a GNU-based compiler such as gcc or
philpem@0 273 djgpp for DOS (available free from www.delorie.com).
philpem@0 274 If you are using a commercial compiler, you may have to modify the makefile
philpem@0 275 or generate your own project file.
philpem@0 276 Also note that part of the compilation process involves the compilation and
philpem@0 277 invokation of the m68kmake program.
philpem@0 278
philpem@0 279 - Copy the m68k files to a directory. Then copy the host environment files to
philpem@0 280 the same directory, overwriting m68kconf.h. program.bin is the actual 68000
philpem@0 281 program you will be running.
philpem@0 282 - Modify osd_get_key() in sim.c to suit your environment (currently set for
philpem@0 283 the free djgpp compiler, available from www.delorie.com, under DOS).
philpem@0 284 - Type make
philpem@0 285 - Perform the necessary animal sacrifices.
philpem@0 286 - Type sim program.bin
philpem@0 287
philpem@0 288
philpem@0 289 Keys:
philpem@0 290 ESC - quits the simulator
philpem@0 291 ~ - generates an NMI interrupt
philpem@0 292 Any other key - Genearate input for the input device
philpem@0 293
philpem@0 294
philpem@0 295 Note: I've cheated a bit in the emulation. There is no speed control
philpem@0 296 to set the speed the CPU runs at; it simply runs as fast as your
philpem@0 297 processor can run it.
philpem@0 298 To add speed control, you will need a high-precision timestamp
philpem@0 299 function (like the RDTSC instruction for newer Pentium CPUs)
philpem@0 300 and a bit of arithmetic to make the cycles argument for m68k_execute().
philpem@0 301 I'll leave that as an excercise to the reader.