src/wd2010.h

Mon, 14 Jan 2013 09:22:12 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Jan 2013 09:22:12 +0000
changeset 118
feee84e0b3bf
parent 116
21521e62007f
permissions
-rw-r--r--

More bus error fixes for FreeBee

I have fixed two more bus error handling bugs in FreeBee. First, the CPU core was executing the instruction regardless of whether a bus error occurs when fetching the opcode (which caused it to execute a bogus instruction in such cases). The other one was related to one of my previous fixes - the jump to the bus error vector was at the beginning of the main loop, so it wouldn't be called immediately after the bus error occurred if the timeslot expired, causing the return address to be off.

With these fixes, Unix now runs enough to get into userspace and run the install script (it is also possible to break out and get a shell prompt). However, many commands segfault semi-randomly (or more specifically, it seems that some child processes forked by the shell might be segfaulting before they can exec the command program), so installing the system isn't possible yet. I am not sure exactly what the bug is, but it seems to be related to some function in the shell returning null when the code calling it is assuming that it won't. What the function is, or why it is returning null, I'm not sure (the shell is built without the shared libc and is stripped, making identifying the function harder). I suspect that the function might be in libc, but that is hard to tell.

Author: Andrew Warkentin <andreww591 gmail com>

philpem@112 1 #ifndef _WD2010_H
philpem@112 2 #define _WD2010_H
philpem@112 3
philpem@112 4 #include <stdbool.h>
philpem@112 5 #include <stddef.h>
philpem@112 6 #include <stdint.h>
philpem@112 7 #include <stdio.h>
philpem@112 8
philpem@112 9 /// WD2010 registers
philpem@112 10 typedef enum {
philpem@116 11 WD2010_REG_ERROR = 1, ///< Error register
philpem@116 12 WD2010_REG_WRITE_PRECOMP_CYLINDER = 1, ///< Write precompensation cylinder register
philpem@116 13 WD2010_REG_SECTOR_COUNT = 2, ///< Sector count register
philpem@116 14 WD2010_REG_SECTOR_NUMBER = 3, ///< Sector number register
philpem@116 15 WD2010_REG_CYLINDER_LOW = 4, ///< Low byte of cylinder
philpem@116 16 WD2010_REG_CYLINDER_HIGH = 5, ///< High byte of cylinder
philpem@116 17 WD2010_REG_SDH = 6, ///< Sector size, drive, and head
philpem@116 18 WD2010_REG_STATUS = 7, ///< Status register
philpem@116 19 WD2010_REG_COMMAND = 7, ///< Command register
philpem@116 20 UNIXPC_REG_MCR2 = 255 ///< UNIX-PC MCR2 register (special!)
philpem@112 21 } WD2010_REG;
philpem@112 22
philpem@112 23 /// WD2010 emulator error codes
philpem@112 24 typedef enum {
philpem@112 25 WD2010_ERR_OK = 0, ///< Operation succeeded
philpem@112 26 WD2010_ERR_BAD_GEOM = -1, ///< Bad geometry, or image file too small
philpem@112 27 WD2010_ERR_NO_MEMORY = -2 ///< Out of memory
philpem@112 28 } WD2010_ERR;
philpem@112 29
philpem@112 30 typedef struct {
philpem@112 31 // Current track, head and sector
philpem@112 32 int track, head, sector;
philpem@112 33 // Geometry of current disc
philpem@112 34 int geom_secsz, geom_spt, geom_heads, geom_tracks;
philpem@112 35 // IRQ status
philpem@112 36 bool irq;
philpem@112 37 // Status of last command
philpem@112 38 uint8_t status;
philpem@112 39 // Error resgister
philpem@112 40 uint8_t error_reg;
philpem@112 41 // Cylinder number registers
philpem@112 42 uint8_t cylinder_high_reg, cylinder_low_reg;
philpem@112 43 // SDH register (sets sector size, drive number, and head number)
philpem@112 44 uint8_t sdh;
philpem@116 45 // MCR2 register (LSB is HDSEL3 - head select bit 3)
philpem@116 46 bool mcr2_hdsel3, mcr2_ddrive1;
philpem@112 47 // Sector number and count registers
philpem@112 48 int sector_number, sector_count;
philpem@112 49 // Last command has the multiple sector flag set?
philpem@112 50 bool multi_sector;
philpem@112 51 // Last command uses DRQ bit?
philpem@112 52 bool cmd_has_drq;
philpem@112 53 // Current write is a format?
philpem@112 54 bool formatting;
philpem@112 55 // Data buffer, current DRQ pointer and length
philpem@112 56 uint8_t *data;
philpem@112 57 size_t data_pos, data_len;
philpem@112 58 // Current disc image file
philpem@112 59 FILE *disc_image;
philpem@112 60 // LBA at which to start writing
philpem@112 61 int write_pos;
philpem@112 62 // Flag to allow delaying DRQ
philpem@112 63 bool drq;
philpem@112 64 } WD2010_CTX;
philpem@112 65
philpem@112 66 /**
philpem@112 67 * @brief Initialise a WD2010 context.
philpem@112 68 * @param ctx WD2010 context.
philpem@112 69 *
philpem@112 70 * This must be run once when the context is created.
philpem@112 71 */
philpem@112 72 int wd2010_init(WD2010_CTX *ctx, FILE *fp, int secsz, int spt, int heads);
philpem@112 73
philpem@112 74 /**
philpem@112 75 * @brief Reset a WD2010 context.
philpem@112 76 * @param ctx WD2010 context.
philpem@112 77 *
philpem@112 78 * This should be run if the WD2010 needs to be reset (MR/ line toggled).
philpem@112 79 */
philpem@112 80 void wd2010_reset(WD2010_CTX *ctx);
philpem@112 81
philpem@112 82 /**
philpem@112 83 * Deinitialise a WD2010 context.
philpem@112 84 * @param ctx WD2010 context.
philpem@112 85 */
philpem@112 86 void wd2010_done(WD2010_CTX *ctx);
philpem@112 87
philpem@112 88 /**
philpem@112 89 * @brief Read IRQ Rising Edge status.
philpem@112 90 * @param ctx WD2010 context.
philpem@112 91 */
philpem@112 92 bool wd2010_get_irq(WD2010_CTX *ctx);
philpem@112 93
philpem@112 94 /**
philpem@112 95 * @brief Read DRQ status.
philpem@112 96 * @param ctx WD2010 context.
philpem@112 97 */
philpem@112 98 bool wd2010_get_drq(WD2010_CTX *ctx);
philpem@112 99
philpem@112 100 /**
philpem@112 101 * @brief Read WD2010 register.
philpem@112 102 * @param ctx WD2010 context
philpem@112 103 * @param addr Register address (0, 1, 2, 3, 4, 5, 6, 7, or 8)
philpem@112 104 */
philpem@112 105 uint8_t wd2010_read_reg(WD2010_CTX *ctx, uint8_t addr);
philpem@112 106
philpem@112 107 /**
philpem@112 108 * @brief Write WD2010 register
philpem@112 109 * @param ctx WD2010 context
philpem@112 110 * @param addr Register address (0, 1, 2, 3, 4, 5, 6, 7, or 8)
philpem@112 111 * @param val Value to write
philpem@112 112 */
philpem@112 113 void wd2010_write_reg(WD2010_CTX *ctx, uint8_t addr, uint8_t val);
philpem@112 114
philpem@112 115 /**
philpem@112 116 * @brief Read a data byte from the data buffer
philpem@112 117 * @param ctx WD2010 context
philpem@112 118 */
philpem@112 119 uint8_t wd2010_read_data(WD2010_CTX *ctx);
philpem@112 120
philpem@112 121 /**
philpem@112 122 * @brief Write a value to the data buffer
philpem@112 123 * @param ctx WD2010 context
philpem@112 124 * @param val Value to write
philpem@112 125 */
philpem@112 126 void wd2010_write_data(WD2010_CTX *ctx, uint8_t val);
philpem@112 127
philpem@112 128 void wd2010_dma_miss(WD2010_CTX *ctx);
philpem@112 129 #endif